Exemple #1
0
 public Tx(uint version, TxIn[] inputs, TxOut[] outputs, uint lockTime)
 {
     this.version = version;
     this.inputs = inputs;
     this.outputs = outputs;
     this.lockTime = lockTime;
 }
		protected override void BuildTransaction(JObject json, Transaction tx)
		{
			var hash = uint256.Parse((string)json.GetValue("hash"));
			tx.Version = (uint)json.GetValue("ver");
			tx.LockTime = (uint)json.GetValue("lock_time");
			var size = (uint)json.GetValue("size");


			var vin = (JArray)json.GetValue("in");
			int vinCount = (int)json.GetValue("vin_sz");
			for(int i = 0 ; i < vinCount ; i++)
			{
				var jsonIn = (JObject)vin[i];
				var txin = new TxIn();
				tx.Inputs.Add(txin);
				var prevout = (JObject)jsonIn.GetValue("prev_out");

				txin.PrevOut.Hash = uint256.Parse((string)prevout.GetValue("hash"));
				txin.PrevOut.N = (uint)prevout.GetValue("n");


				var script = (string)jsonIn.GetValue("scriptSig");
				if(script != null)
				{
					txin.ScriptSig = new Script(script);
				}
				else
				{
					var coinbase = (string)jsonIn.GetValue("coinbase");
					txin.ScriptSig = new Script(Encoders.Hex.DecodeData(coinbase));
				}

				var seq = jsonIn.GetValue("sequence");
				if(seq != null)
				{
					txin.Sequence = (uint)seq;
				}
			}

			var vout = (JArray)json.GetValue("out");
			int voutCount = (int)json.GetValue("vout_sz");
			for(int i = 0 ; i < voutCount ; i++)
			{
				var jsonOut = (JObject)vout[i];
				var txout = new NBitcoin.TxOut();
				tx.Outputs.Add(txout);

				txout.Value = Money.Parse((string)jsonOut.GetValue("value"));
				txout.ScriptPubKey = new Script((string)jsonOut.GetValue("scriptPubKey"));
			}
		}
Exemple #3
0
		protected override void BuildTransaction(JObject json, Transaction tx)
		{
			var txid = uint256.Parse((string)json.GetValue("txid"));
			tx.Version = (uint)json.GetValue("version");
			tx.LockTime = (uint)json.GetValue("locktime");

			var vin = (JArray)json.GetValue("vin");
			for(int i = 0 ; i < vin.Count ; i++)
			{
				var jsonIn = (JObject)vin[i];
				var txin = new TxIn();
				tx.Inputs.Add(txin);

				var script = (JObject)jsonIn.GetValue("scriptSig");
				if(script != null)
				{
					txin.ScriptSig = new Script(Encoders.Hex.DecodeData((string)script.GetValue("hex")));
					txin.PrevOut.Hash = uint256.Parse((string)jsonIn.GetValue("txid"));
					txin.PrevOut.N = (uint)jsonIn.GetValue("vout");
				}
				else
				{
					var coinbase = (string)jsonIn.GetValue("coinbase");
					txin.ScriptSig = new Script(Encoders.Hex.DecodeData(coinbase));
				}

				txin.Sequence = (uint)jsonIn.GetValue("sequence");

			}

			var vout = (JArray)json.GetValue("vout");
			for(int i = 0 ; i < vout.Count ; i++)
			{
				var jsonOut = (JObject)vout[i];
				var txout = new TxOut();
				tx.Outputs.Add(txout);

				var btc = (decimal)jsonOut.GetValue("value");
				var satoshis = btc * Money.COIN;
				txout.Value = new Money((long)(satoshis));

				var script = (JObject)jsonOut.GetValue("scriptPubKey");
				txout.ScriptPubKey = new Script(Encoders.Hex.DecodeData((string)script.GetValue("hex")));
			}
		}
Exemple #4
0
        // This interface implementation method is only used by the Tumbler server
        public async Task <Transaction> ReceiveAsync(ScriptCoin escrowedCoin, TransactionSignature clientSignature, Key escrowKey, FeeRate feeRate)
        {
            var input = new ClientEscapeData()
            {
                ClientSignature = clientSignature,
                EscrowedCoin    = escrowedCoin,
                EscrowKey       = escrowKey
            };

            var cashout = await GenerateAddressAsync();

            var tx = new Transaction();

            // Note placeholders - this step is performed again further on
            var txin = new TxIn(input.EscrowedCoin.Outpoint);

            txin.ScriptSig = new Script(
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(input.EscrowedCoin.Redeem.ToBytes())
                );
            txin.Witnessify();
            tx.AddInput(txin);

            tx.Outputs.Add(new TxOut()
            {
                ScriptPubKey = cashout.ScriptPubKey,
                Value        = input.EscrowedCoin.Amount
            });

            ScriptCoin[] coinArray = { input.EscrowedCoin };

            var currentFee = tx.GetFee(coinArray);

            tx.Outputs[0].Value -= feeRate.GetFee(tx) - currentFee;

            var txin2     = tx.Inputs[0];
            var signature = tx.SignInput(input.EscrowKey, input.EscrowedCoin);

            txin2.ScriptSig = new Script(
                Op.GetPushOp(input.ClientSignature.ToBytes()),
                Op.GetPushOp(signature.ToBytes()),
                Op.GetPushOp(input.EscrowedCoin.Redeem.ToBytes())
                );
            txin2.Witnessify();

            //LogDebug("Trying to broadcast transaction: " + tx.GetHash());

            await this.TumblingState.BroadcasterManager.BroadcastTransactionAsync(tx).ConfigureAwait(false);

            var bcResult = TumblingState.BroadcasterManager.GetTransaction(tx.GetHash()).State;

            switch (bcResult)
            {
            case Stratis.Bitcoin.Broadcasting.State.Broadcasted:
            case Stratis.Bitcoin.Broadcasting.State.Propagated:
                //LogDebug("Broadcasted transaction: " + tx.GetHash());
                break;

            case Stratis.Bitcoin.Broadcasting.State.ToBroadcast:
                // Wait for propagation
                var waited = TimeSpan.Zero;
                var period = TimeSpan.FromSeconds(1);
                while (TimeSpan.FromSeconds(21) > waited)
                {
                    // Check BroadcasterManager for broadcast success
                    var transactionEntry = this.TumblingState.BroadcasterManager.GetTransaction(tx.GetHash());
                    if (transactionEntry != null && transactionEntry.State == Stratis.Bitcoin.Broadcasting.State.Propagated)
                    {
                        //LogDebug("Propagated transaction: " + tx.GetHash());
                    }
                    await Task.Delay(period).ConfigureAwait(false);

                    waited += period;
                }
                break;

            case Stratis.Bitcoin.Broadcasting.State.CantBroadcast:
                // Do nothing
                break;
            }

            //LogDebug("Uncertain if transaction was propagated: " + tx.GetHash());

            return(tx);
        }
 public static RPCTransactionInput ToRPCInputs(this TxIn txin)
 {
     return(new RPCTransactionInput(txin));
 }
Exemple #6
0
        public Block[] GenerateStratis(int blockCount, List <Transaction> passedTransactions = null, bool broadcast = true)
        {
            var            fullNode = (this.runner as StratisBitcoinPowRunner).FullNode;
            BitcoinSecret  dest     = this.MinerSecret;
            List <Block>   blocks   = new List <Block>();
            DateTimeOffset now      = this.MockTime == null ? DateTimeOffset.UtcNow : this.MockTime.Value;

#if !NOSOCKET
            for (int i = 0; i < blockCount; i++)
            {
                uint  nonce = 0;
                Block block = new Block();
                block.Header.HashPrevBlock = fullNode.Chain.Tip.HashBlock;
                block.Header.Bits          = block.Header.GetWorkRequired(fullNode.Network, fullNode.Chain.Tip);
                block.Header.UpdateTime(now, fullNode.Network, fullNode.Chain.Tip);
                var coinbase = new Transaction();
                coinbase.AddInput(TxIn.CreateCoinbase(fullNode.Chain.Height + 1));
                coinbase.AddOutput(new TxOut(fullNode.Network.GetReward(fullNode.Chain.Height + 1), dest.GetAddress()));
                block.AddTransaction(coinbase);
                if (passedTransactions?.Any() ?? false)
                {
                    passedTransactions = this.Reorder(passedTransactions);
                    block.Transactions.AddRange(passedTransactions);
                }
                block.UpdateMerkleRoot();
                while (!block.CheckProofOfWork(fullNode.Network.Consensus))
                {
                    block.Header.Nonce = ++nonce;
                }
                blocks.Add(block);
                if (broadcast)
                {
                    uint256 blockHash = block.GetHash();
                    var     newChain  = new ChainedBlock(block.Header, blockHash, fullNode.Chain.Tip);
                    var     oldTip    = fullNode.Chain.SetTip(newChain);
                    fullNode.ConsensusLoop().Puller.InjectBlock(blockHash, new DownloadedBlock {
                        Length = block.GetSerializedSize(), Block = block
                    }, CancellationToken.None);

                    //try
                    //{
                    //    var blockResult = new BlockResult { Block = block };
                    //    fullNode.ConsensusLoop.AcceptBlock(blockResult);

                    //    // similar logic to what's in the full node code
                    //    if (blockResult.Error == null)
                    //    {
                    //        fullNode.ChainBehaviorState.ConsensusTip = fullNode.ConsensusLoop.Tip;
                    //        //if (fullNode.Chain.Tip.HashBlock == blockResult.ChainedBlock.HashBlock)
                    //        //{
                    //        //    var unused = cache.FlushAsync();
                    //        //}
                    //        fullNode.Signals.Blocks.Broadcast(block);
                    //    }
                    //}
                    //catch (ConsensusErrorException)
                    //{
                    //    // set back the old tip
                    //    fullNode.Chain.SetTip(oldTip);
                    //}
                }
            }

            return(blocks.ToArray());
#endif
        }
Exemple #7
0
 /// <inheritdoc/>
 protected override bool CheckInput(Transaction tx, int inputIndexCopy, TxOut txout, PrecomputedTransactionData txData, TxIn input, DeploymentFlags flags)
 {
     return(this.logic.CheckInput(base.CheckInput, tx, inputIndexCopy, txout, txData, input, flags));
 }
        /// <inheritdoc />
        public override async Task RunAsync(RuleContext context)
        {
            Block            block = context.ValidationContext.BlockToValidate;
            ChainedHeader    index = context.ValidationContext.ChainedHeaderToValidate;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = (context as UtxoRuleContext).UnspentOutputSet;

            long  sigOpsCost  = 0;
            Money fees        = Money.Zero;
            var   checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                Transaction tx = block.Transactions[txIndex];

                if (!context.SkipValidation)
                {
                    if (!tx.IsCoinBase && !view.HaveInputs(tx))
                    {
                        this.Logger.LogTrace("Transaction '{0}' has not inputs", tx.GetHash());
                        this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                        ConsensusErrors.BadTransactionMissingInput.Throw();
                    }

                    if (!this.IsTxFinal(tx, context))
                    {
                        this.Logger.LogTrace("Transaction '{0}' is not final", tx.GetHash());
                        this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                        ConsensusErrors.BadTransactionNonFinal.Throw();
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.ConsensusOptions.MaxBlockSigopsCost)
                    {
                        this.Logger.LogTrace("(-)[BAD_BLOCK_SIG_OPS]");
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    if (!tx.IsCoinBase)
                    {
                        this.CheckInputs(tx, view, index.Height);

                        if (!tx.IsCoinStake)
                        {
                            fees += view.GetValueIn(tx) - tx.TotalOut;
                        }

                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() => this.CheckInput(tx, inputIndexCopy, txout, txData, input, flags));
                            checkInput.Start();
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                foreach (Task <bool> checkInput in checkInputs)
                {
                    if (await checkInput.ConfigureAwait(false))
                    {
                        continue;
                    }

                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }
        }
 /// <summary>
 /// Gets the transaction output for a transaction input.
 /// </summary>
 /// <param name="input">Transaction input.</param>
 /// <returns>Transaction output.</returns>
 public TxOut GetOutputFor(TxIn input)
 {
     return(this.Set.GetOutputFor(input));
 }
Exemple #10
0
        /// <summary>
        /// Determines whether or not the input's address exists in the wallet's set of addresses.
        /// </summary>
        /// <param name="addresses">The wallet's external and internal addresses.</param>
        /// <param name="txDictionary">The set of transactions to check against.</param>
        /// <param name="txIn">The input to check.</param>
        /// <returns><c>true</c>if the input's address exist in the wallet.</returns>
        private bool IsTxInMine(IEnumerable <HdAddress> addresses, Dictionary <uint256, TransactionData> txDictionary, TxIn txIn)
        {
            TransactionData previousTransaction = null;

            txDictionary.TryGetValue(txIn.PrevOut.Hash, out previousTransaction);

            if (previousTransaction == null)
            {
                return(false);
            }

            var previousTx = this.blockStore.GetTransactionById(previousTransaction.Id);

            if (txIn.PrevOut.N >= previousTx.Outputs.Count)
            {
                return(false);
            }

            // We now need to check if the scriptPubkey is in our wallet.
            // See https://github.com/bitcoin/bitcoin/blob/011c39c2969420d7ca8b40fbf6f3364fe72da2d0/src/script/ismine.cpp
            return(IsAddressMine(addresses, previousTx.Outputs[txIn.PrevOut.N].ScriptPubKey));
        }
        /// <inheritdoc />
        public override async Task RunAsync(RuleContext context)
        {
            Block            block = context.ValidationContext.BlockToValidate;
            ChainedHeader    index = context.ValidationContext.ChainedHeaderToValidate;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = (context as UtxoRuleContext).UnspentOutputSet;

            long  sigOpsCost    = 0;
            Money fees          = Money.Zero;
            var   inputsToCheck = new List <(Transaction tx, int inputIndexCopy, TxOut txOut, PrecomputedTransactionData txData, TxIn input, DeploymentFlags flags)>();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                Transaction tx = block.Transactions[txIndex];

                if (!context.SkipValidation)
                {
                    if (!tx.IsCoinBase && !view.HaveInputs(tx))
                    {
                        this.Logger.LogDebug("Transaction '{0}' has no inputs", tx.GetHash());
                        this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                        ConsensusErrors.BadTransactionMissingInput.Throw();
                    }

                    if (!this.IsTxFinal(tx, context))
                    {
                        this.Logger.LogDebug("Transaction '{0}' is not final", tx.GetHash());
                        this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                        ConsensusErrors.BadTransactionNonFinal.Throw();
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.ConsensusOptions.MaxBlockSigopsCost)
                    {
                        this.Logger.LogTrace("(-)[BAD_BLOCK_SIG_OPS]");
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    if (!tx.IsCoinBase)
                    {
                        this.CheckInputs(tx, view, index.Height);

                        fees += this.GetTransactionFee(view, tx);

                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            TxIn input = tx.Inputs[inputIndex];

                            TxOut prevOut = view.GetOutputFor(input);

                            // If there are any consensus-specific requirements to inhibit spends from or to particular scripts, they get enforced here.
                            this.AllowSpend(prevOut, tx);

                            inputsToCheck.Add((
                                                  tx: tx,
                                                  inputIndexCopy: inputIndex,
                                                  txOut: prevOut,
                                                  txData,
                                                  input: input,
                                                  flags
                                                  ));
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                // Start the Parallel loop on a thread so its result can be awaited rather than blocking
                Task <ParallelLoopResult> checkInputsInParallel = Task.Run(() =>
                {
                    return(Parallel.ForEach(inputsToCheck, (input, state) =>
                    {
                        if (state.ShouldExitCurrentIteration)
                        {
                            return;
                        }

                        if (!this.CheckInput(input.tx, input.inputIndexCopy, input.txOut, input.txData, input.input, input.flags))
                        {
                            state.Stop();
                        }
                    }));
                });

                ParallelLoopResult loopResult = await checkInputsInParallel.ConfigureAwait(false);

                if (!loopResult.IsCompleted)
                {
                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");

                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogDebug("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }
        }
Exemple #12
0
		private void CanVerifySequenceLockCore(Sequence[] sequences, int[] prevHeights, int currentHeight, DateTimeOffset first, bool expected, SequenceLock expectedLock)
		{
			ConcurrentChain chain = new ConcurrentChain(new BlockHeader()
			{
				BlockTime = first
			});
			first = first + TimeSpan.FromMinutes(10);
			while(currentHeight != chain.Height)
			{
				chain.SetTip(new BlockHeader()
				{
					BlockTime = first,
					HashPrevBlock = chain.Tip.HashBlock
				});
				first = first + TimeSpan.FromMinutes(10);
			}
			Transaction tx = new Transaction();
			tx.Version = 2;
			for(int i = 0 ; i < sequences.Length ; i++)
			{
				TxIn input = new TxIn();
				input.Sequence = sequences[i];
				tx.Inputs.Add(input);
			}
			Assert.Equal(expected, tx.CheckSequenceLocks(prevHeights, chain.Tip));
			var actualLock = tx.CalculateSequenceLocks(prevHeights, chain.Tip);
			Assert.Equal(expectedLock.MinTime, actualLock.MinTime);
			Assert.Equal(expectedLock.MinHeight, actualLock.MinHeight);
		}
        /// <summary>
        /// Whether transaction inputs are standard.
        /// Check for standard transaction types.
        /// </summary>
        /// <seealso>https://github.com/bitcoin/bitcoin/blob/febf3a856bcfb8fef2cb4ddcb8d1e0cab8a22580/src/policy/policy.cpp#L156</seealso>
        /// <param name="tx">Transaction to verify.</param>
        /// <param name="mapInputs">Map of previous transactions that have outputs we're spending.</param>
        /// <returns>Whether all inputs (scriptSigs) use only standard transaction forms.</returns>
        private bool AreInputsStandard(Network network, Transaction tx, MempoolCoinView mapInputs)
        {
            if (tx.IsCoinBase)
            {
                this.logger.LogTrace("(-)[IS_COINBASE]:true");
                return(true); // Coinbases don't use vin normally.
            }

            for (int i = 0; i < tx.Inputs.Count; i++)
            {
                TxIn           txin     = tx.Inputs[i];
                TxOut          prev     = mapInputs.GetOutputFor(txin);
                ScriptTemplate template = network.StandardScriptsRegistry.GetTemplateFromScriptPubKey(prev.ScriptPubKey);
                if (template == null) // i.e. the TX_NONSTANDARD case
                {
                    this.logger.LogTrace("(-)[BAD_SCRIPT_TEMPLATE]:false");
                    return(false);
                }

                /* Check transaction inputs to mitigate two potential denial-of-service attacks:
                 *
                 * 1. scriptSigs with extra data stuffed into them, not consumed by scriptPubKey (or P2SH script)
                 * 2. P2SH scripts with a crazy number of expensive CHECKSIG/CHECKMULTISIG operations
                 *
                 * Why bother? To avoid denial-of-service attacks; an attacker can submit a standard HASH... OP_EQUAL transaction,
                 * which will get accepted into blocks. The redemption script can be anything; an attacker could use a very
                 * expensive-to-check-upon-redemption script like:
                 *   DUP CHECKSIG DROP ... repeated 100 times... OP_1
                 */
                if (template.Type == TxOutType.TX_SCRIPTHASH)
                {
                    // Convert the scriptSig into a stack, so we can inspect the redeemScript.
                    var ctx = new ScriptEvaluationContext(this.network)
                    {
                        ScriptVerify = ScriptVerify.None
                    };

                    if (!ctx.EvalScript(txin.ScriptSig, tx, i)) // TODO: Check the semantics of SigVersion::BASE from original code
                    {
                        return(false);
                    }

                    // TODO: Investigate why IsEmpty is failing to return true when there is nothing on the stack. It is possible that nowhere else in the codebase is using IsEmpty on an IEnumerable
                    if (ctx.Stack.IsEmpty() || ctx.Stack.Count == 0)
                    {
                        return(false);
                    }

                    // Get redeemScript from stack.
                    var redeemScript = new Script(ctx.Stack.Top(-1));

                    if (redeemScript.GetSigOpCount(true) > MaxP2SHSigOps)
                    {
                        this.logger.LogTrace("(-)[SIG_OP_MAX]:false");
                        return(false);
                    }
                }
            }

            return(true);
        }
        public TransactionPolicyError[] Check(Transaction transaction, ICoin[] spentCoins)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }

            spentCoins = spentCoins ?? new ICoin[0];

            var errors = new List <TransactionPolicyError>();



            foreach (IndexedTxIn input in transaction.Inputs.AsIndexedInputs())
            {
                ICoin coin = spentCoins.FirstOrDefault(s => s.Outpoint == input.PrevOut);
                if (coin != null)
                {
                    if (this.ScriptVerify != null)
                    {
                        ScriptError error;
                        if (!VerifyScript(input, coin.TxOut.ScriptPubKey, coin.TxOut.Value, this.ScriptVerify.Value, out error))
                        {
                            errors.Add(new ScriptPolicyError(input, error, this.ScriptVerify.Value, coin.TxOut.ScriptPubKey));
                        }
                    }
                }

                TxIn txin = input.TxIn;
                if (txin.ScriptSig.Length > MaxScriptSigLength)
                {
                    errors.Add(new InputPolicyError("Max scriptSig length exceeded actual is " + txin.ScriptSig.Length + ", max is " + MaxScriptSigLength, input));
                }
                if (!txin.ScriptSig.IsPushOnly)
                {
                    errors.Add(new InputPolicyError("All operation should be push", input));
                }
                if (!txin.ScriptSig.HasCanonicalPushes)
                {
                    errors.Add(new InputPolicyError("All operation should be canonical push", input));
                }
            }

            if (this.CheckMalleabilitySafe)
            {
                foreach (IndexedTxIn input in transaction.Inputs.AsIndexedInputs())
                {
                    ICoin coin = spentCoins.FirstOrDefault(s => s.Outpoint == input.PrevOut);
                    if (coin != null && coin.GetHashVersion(this.network) != HashVersion.Witness)
                    {
                        errors.Add(new InputPolicyError("Malleable input detected", input));
                    }
                }
            }

            if (this.CheckScriptPubKey)
            {
                foreach (Coin txout in transaction.Outputs.AsCoins())
                {
                    ScriptTemplate template = StandardScripts.GetTemplateFromScriptPubKey(txout.ScriptPubKey);
                    if (template == null)
                    {
                        errors.Add(new OutputPolicyError("Non-Standard scriptPubKey", (int)txout.Outpoint.N));
                    }
                }
            }

            int txSize = transaction.GetSerializedSize();

            if (this.MaxTransactionSize != null)
            {
                if (txSize >= this.MaxTransactionSize.Value)
                {
                    errors.Add(new TransactionSizePolicyError(txSize, this.MaxTransactionSize.Value));
                }
            }

            Money fees = transaction.GetFee(spentCoins);

            if (fees != null)
            {
                if (this.CheckFee)
                {
                    if (this.MaxTxFee != null)
                    {
                        Money max = this.MaxTxFee.GetFee(txSize);
                        if (fees > max)
                        {
                            errors.Add(new FeeTooHighPolicyError(fees, max));
                        }
                    }

                    if (this.MinRelayTxFee != null)
                    {
                        if (this.MinRelayTxFee != null)
                        {
                            Money min = this.MinRelayTxFee.GetFee(txSize);
                            if (fees < min)
                            {
                                errors.Add(new FeeTooLowPolicyError(fees, min));
                            }
                        }
                    }
                }
            }
            if (this.MinRelayTxFee != null)
            {
                foreach (TxOut output in transaction.Outputs)
                {
                    byte[] bytes = output.ScriptPubKey.ToBytes(true);
                    if (output.IsDust(this.MinRelayTxFee) && !IsOpReturn(bytes))
                    {
                        errors.Add(new DustPolicyError(output.Value, output.GetDustThreshold(this.MinRelayTxFee)));
                    }
                }
            }
            int opReturnCount = transaction.Outputs.Select(o => o.ScriptPubKey.ToBytes(true)).Count(b => IsOpReturn(b));

            if (opReturnCount > 1)
            {
                errors.Add(new TransactionPolicyError("More than one op return detected"));
            }
            return(errors.ToArray());
        }
        /// <summary>
        /// Validates transaction inputs against transaction data for a specific set of script verify flags.
        /// Check whether all inputs of this transaction are valid (no double spends, scripts & signatures, amounts)
        /// This does not modify the UTXO set.
        /// </summary>
        /// <seealso>https://github.com/bitcoin/bitcoin/blob/febf3a856bcfb8fef2cb4ddcb8d1e0cab8a22580/src/validation.cpp#L1259</seealso>
        /// <param name="ruleContext">Current mempool rule context.</param>
        /// <param name="context">Current validation context.</param>
        /// <param name="scriptVerify">Script verify flag.</param>
        /// <param name="txData">Transaction data.</param>
        /// <returns>Whether inputs are valid.</returns>
        private bool CheckInputs(MempoolValidationContext context, ScriptVerify scriptVerify, PrecomputedTransactionData txData)
        {
            Transaction tx = context.Transaction;

            if (tx.IsCoinBase)
            {
                return(true);
            }

            // TODO: The original code does not appear to do these checks here. Reevaluate if this needs to be done, or perhaps moved to another rule/method.
            this.consensusRuleEngine.GetRule <CoinViewRule>().CheckInputs(context.Transaction, context.View.Set, this.chainIndexer.Height + 1);

            // TODO: Original code has the concept of a script execution cache. This might be worth looking into for performance improvements. Signature checks are expensive.

            for (int iInput = 0; iInput < tx.Inputs.Count; iInput++)
            {
                TxIn  input   = tx.Inputs[iInput];
                int   iiInput = iInput;
                TxOut txout   = context.View.GetOutputFor(input);

                var checker = new TransactionChecker(tx, iiInput, txout.Value, txData);
                var ctx     = new ScriptEvaluationContext(this.network)
                {
                    ScriptVerify = scriptVerify
                };
                if (!ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker))
                {
                    if ((scriptVerify & ScriptVerify.StandardNotMandatory) == ScriptVerify.StandardNotMandatory)
                    {
                        // Check whether the failure was caused by a non-mandatory script verification check, such as
                        // non-standard DER encodings or non-null dummy arguments; if so, don't trigger DoS protection to
                        // avoid splitting the network between upgraded and non-upgraded nodes.

                        // TODO: Investigate whether the checker and context can be reused instead of recreated. Probably not.
                        checker = new TransactionChecker(tx, iiInput, txout.Value, txData);
                        ctx     = new ScriptEvaluationContext(this.network)
                        {
                            ScriptVerify = (scriptVerify & ~ScriptVerify.StandardNotMandatory)
                        };

                        if (ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker))
                        {
                            this.logger.LogTrace("(-)[FAIL_NON_MANDATORY_SCRIPT_VERIFY]");
                            this.logger.LogDebug("Failed non-mandatory script verify: Transaction = {0}, scriptVerify = {1}, ctx.scriptVerify = {2}",
                                                 tx.ToHex(), scriptVerify, ctx.ScriptVerify);

                            // TODO: Check what this actually means in Core's logic. If it is on testnet/regtest and RequireStandard is false, is the transaction still rejected?
                            context.State.Fail(MempoolErrors.NonMandatoryScriptVerifyFlagFailed, ctx.Error.ToString()).Throw();
                        }
                    }

                    // Failures of other flags indicate a transaction that is invalid in new blocks, e.g. an invalid P2SH. We DoS ban
                    // such nodes as they are not following the protocol. That said, during an upgrade careful thought should be taken
                    // as to the correct behavior - we may want to continue peering with non-upgraded nodes even after soft-fork
                    // super-majority signaling has occurred.

                    // Further comment from Bitcoin Core:
                    // MANDATORY flag failures correspond to
                    // ValidationInvalidReason::CONSENSUS. Because CONSENSUS
                    // failures are the most serious case of validation
                    // failures, we may need to consider using
                    // RECENT_CONSENSUS_CHANGE for any script failure that
                    // could be due to non-upgraded nodes which we may want to
                    // support, to avoid splitting the network (but this
                    // depends on the details of how net_processing handles
                    // such errors).

                    this.logger.LogTrace("(-)[FAIL_MANDATORY_SCRIPT_VERIFY]");
                    context.State.Fail(MempoolErrors.MandatoryScriptVerifyFlagFailed, ctx.Error.ToString()).Throw();
                }
            }

            return(true);
        }
Exemple #16
0
        public static void Main(string[] args)
        {
            WriteLine("Howdy friend, I am your Bitcoin genie. What's your wish?");
            var command = ReadLine();

            if (command == "I want to know a scriptPubKey")
            {
                WriteLine("Sure, I'll help you, what is the bitcoin address?");
                var addressString = ReadLine();
                var address       = BitcoinAddress.Create(addressString, Network.TestNet);
                WriteLine(address.ScriptPubKey);
            }
            if (command == "I want to create a transaction")
            {
                WriteLine("Great, here is a template for your transaction:");
                WriteLine();
                var tx = Transaction.Create(Network.TestNet);
                WriteLine(tx);
                WriteLine();

                WriteLine("Specify its inputs and outputs for me");
                WriteLine("First the inputs");

                WriteLine("What is the id of the transaction that you want to spend?");
                var prevOutTxId = new uint256(ReadLine());

                WriteLine("Which output of it do you want to spend? What is its id?");
                var prevOutN = int.Parse(ReadLine());
                var outPoint = new OutPoint(prevOutTxId, prevOutN);
                var txIn     = new TxIn(outPoint);
                tx.Inputs.Add(txIn);

                WriteLine("Awesome, here is how your transaction looks like now:");
                WriteLine();
                WriteLine(tx);
                WriteLine();

                WriteLine("Now let's contruct the output");
                WriteLine("What is the scriptPubKey you want to send your bitcoins to?");
                var scriptPubKey = new Script(ReadLine());
                WriteLine("How much bitcoins you want to send there?");
                var amount = new Money(Convert.ToDecimal(ReadLine(), CultureInfo.InvariantCulture), MoneyUnit.BTC);
                tx.Outputs.Add(new TxOut(amount, scriptPubKey));

                WriteLine("Awesome, here is how your transaction looks like now:");
                WriteLine();
                WriteLine(tx);
                WriteLine();

                WriteLine("Now tell me your privateKey so I can sign the transaction:");
                var privKey = new BitcoinSecret(ReadLine());
                tx.Inputs.First().ScriptSig = privKey.ScriptPubKey;

                var coins = tx.Inputs.Select(txin => new Coin(txin.PrevOut, new TxOut {
                    ScriptPubKey = txin.ScriptSig
                }));

                tx.Sign(privKey, coins.ToArray());
                WriteLine($"You signed your transaction on the {privKey.Network}");

                WriteLine("Here is how your final transaction looks like:");
                WriteLine();
                WriteLine(tx);
                WriteLine();

                WriteLine("Here is the hex of your transaction:");
                WriteLine();
                WriteLine(tx.ToHex());
                WriteLine();
            }

            WriteLine("Press enter to exit...");
            ReadLine();
        }
        /// <summary>Processes block that was added or removed from consensus chain.</summary>
        private void ProcessBlockAddedOrRemoved(KeyValuePair <bool, ChainedHeaderBlock> item)
        {
            // Make sure it's on top of the tip.
            bool blockAdded = item.Key;

            Block block         = item.Value.Block;
            int   currentHeight = item.Value.ChainedHeader.Height;

            // Process inputs
            var inputs = new List <TxIn>();

            // Collect all inputs excluding coinbases.
            foreach (TxInList inputsCollection in block.Transactions.Where(x => !x.IsCoinBase).Select(x => x.Inputs))
            {
                inputs.AddRange(inputsCollection);
            }

            Transaction[] transactions = this.blockStore.GetTransactionsByIds(inputs.Select(x => x.PrevOut.Hash).ToArray());

            // TODO is it possible that transactions is null because block with requested ID was reorged away already?

            for (int i = 0; i < inputs.Count; i++)
            {
                TxIn currentInput = inputs[i];

                TxOut txOut = transactions[i].Outputs[currentInput.PrevOut.N];

                Money amountSpent = txOut.Value;

                AddressIndexData addrData = this.GetOrCreateAddressData(txOut.ScriptPubKey);

                if (blockAdded)
                {
                    // Record money being spent.
                    addrData.Changes.Add(new AddressBalanceChange()
                    {
                        BalanceChangedHeight = currentHeight,
                        Satoshi   = amountSpent.Satoshi,
                        Deposited = false
                    });
                }
                else
                {
                    // Remove changes.
                    addrData.Changes.RemoveAll(x => x.BalanceChangedHeight == currentHeight);
                }
            }

            // Process outputs.
            foreach (Transaction tx in block.Transactions)
            {
                foreach (TxOut txOut in tx.Outputs)
                {
                    Money amountReceived = txOut.Value;

                    AddressIndexData addrData = this.GetOrCreateAddressData(txOut.ScriptPubKey);

                    if (blockAdded)
                    {
                        // Record money being sent.
                        addrData.Changes.Add(new AddressBalanceChange()
                        {
                            BalanceChangedHeight = currentHeight,
                            Satoshi   = amountReceived.Satoshi,
                            Deposited = true
                        });
                    }
                    else
                    {
                        // Remove changes.
                        addrData.Changes.RemoveAll(x => x.BalanceChangedHeight == currentHeight);
                    }
                }
            }

            this.addressesIndex.TipHash = item.Value.ChainedHeader.HashBlock.ToString();
        }
Exemple #18
0
        public dynamic SendToTestNet(dynamic transactionDto, string toAddress, string privateKey, string network, string token)
        {
            try
            {
                var btcnetwork = GetNetwork(network);


                BitcoinSecret        secret = new BitcoinSecret(privateKey, btcnetwork);
                NBitcoin.Transaction tx     = NBitcoin.Transaction.Create(btcnetwork);
                TxIn input = new TxIn
                {
                    PrevOut   = new OutPoint(new uint256(transactionDto.TransactionID), transactionDto.Vout),
                    ScriptSig = secret.GetAddress(ScriptPubKeyType.Legacy).ScriptPubKey
                };
                tx.Inputs.Add(input);

                TxOut output      = new TxOut();
                Money fee         = Money.Coins(transactionDto.DefaultFees);
                Money totalAmount = Money.Coins(transactionDto.Amount);
                output.Value = totalAmount - fee;
                BitcoinAddress toaddress = BitcoinAddress.Create(toAddress, btcnetwork);
                output.ScriptPubKey = toaddress.ScriptPubKey;
                tx.Outputs.Add(output);

                var coins = tx.Inputs.Select(txin => new Coin(txin.PrevOut, new TxOut {
                    ScriptPubKey = txin.ScriptSig
                }));
                tx.Sign(secret, coins.ToArray());

                /* Push Data to So Chain*/
                string api            = "https://chain.so/api/v2/send_tx/LTCTEST";
                var    httpWebRequest = (HttpWebRequest)WebRequest.Create(api);
                httpWebRequest.ContentType = "application/json; charset=utf-8";
                httpWebRequest.Method      = HttpMethod.Post.Method;
                dynamic reqObj = new ExpandoObject();
                reqObj.tx_hex = tx.ToHex();
                string payload = JsonConvert.SerializeObject(reqObj);

                using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
                {
                    streamWriter.Write(payload);
                    var ss = streamWriter.ToString();
                    streamWriter.Flush();
                }
                string responseData = string.Empty;
                var    httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                {
                    responseData = streamReader.ReadToEnd();
                }
                dynamic response = new ExpandoObject();
                if (!string.IsNullOrWhiteSpace(responseData))
                {
                    response = JsonConvert.DeserializeObject(responseData);
                }

                return(response);
            }
            catch (Exception ex)
            {
                throw new Exception();
            }
        }
Exemple #19
0
        /// <inheritdoc />
        public async override Task RunAsync(RuleContext context)
        {
            this.Logger.LogTrace("()");

            this.blockTxsProcessed = new List <Transaction>();
            NBitcoin.Block   block = context.ValidationContext.Block;
            ChainedHeader    index = context.ValidationContext.ChainedHeader;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = ((UtxoRuleContext)context).UnspentOutputSet;

            this.Parent.PerformanceCounter.AddProcessedBlocks(1);

            // Start state from previous block's root
            this.smartContractParent.OriginalStateRoot.SyncToRoot(((SmartContractBlockHeader)context.ConsensusTip.Header).HashStateRoot.ToBytes());
            IContractStateRepository trackedState = this.smartContractParent.OriginalStateRoot.StartTracking();

            this.refundCounter = 1;
            long  sigOpsCost  = 0;
            Money fees        = Money.Zero;
            var   checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                this.Parent.PerformanceCounter.AddProcessedTransactions(1);
                Transaction tx = block.Transactions[txIndex];
                if (!context.SkipValidation)
                {
                    if (!this.IsProtocolTransaction(tx))
                    {
                        if (!view.HaveInputs(tx))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                            ConsensusErrors.BadTransactionMissingInput.Throw();
                        }

                        var prevheights = new int[tx.Inputs.Count];
                        // Check that transaction is BIP68 final.
                        // BIP68 lock checks (as opposed to nLockTime checks) must
                        // be in ConnectBlock because they require the UTXO set.
                        for (int j = 0; j < tx.Inputs.Count; j++)
                        {
                            prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                        }

                        if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                            ConsensusErrors.BadTransactionNonFinal.Throw();
                        }
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.PowConsensusOptions.MaxBlockSigopsCost)
                    {
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    if (!this.IsProtocolTransaction(tx))
                    {
                        this.CheckInputs(tx, view, index.Height);
                        fees += view.GetValueIn(tx) - tx.TotalOut;
                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            this.Parent.PerformanceCounter.AddProcessedInputs(1);
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() =>
                            {
                                if (txout.ScriptPubKey.IsSmartContractExec() || txout.ScriptPubKey.IsSmartContractInternalCall())
                                {
                                    return(input.ScriptSig.IsSmartContractSpend());
                                }

                                var checker      = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
                                var ctx          = new ScriptEvaluationContext(this.Parent.Network);
                                ctx.ScriptVerify = flags.ScriptFlags;
                                return(ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker));
                            });

                            checkInput.Start();
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);

                this.blockTxsProcessed.Add(tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                foreach (Task <bool> checkInput in checkInputs)
                {
                    if (await checkInput.ConfigureAwait(false))
                    {
                        continue;
                    }

                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }

            if (new uint256(this.smartContractParent.OriginalStateRoot.Root) != ((SmartContractBlockHeader)block.Header).HashStateRoot)
            {
                SmartContractConsensusErrors.UnequalStateRoots.Throw();
            }

            this.smartContractParent.OriginalStateRoot.Commit();

            this.Logger.LogTrace("(-)");
        }
Exemple #20
0
        public bool CheckInput(Func <Transaction, int, TxOut, PrecomputedTransactionData, TxIn, DeploymentFlags, bool> baseCheckInput, Transaction tx, int inputIndexCopy, TxOut txout, PrecomputedTransactionData txData, TxIn input, DeploymentFlags flags)
        {
            if (txout.ScriptPubKey.IsSmartContractExec() || txout.ScriptPubKey.IsSmartContractInternalCall())
            {
                return(input.ScriptSig.IsSmartContractSpend());
            }

            return(baseCheckInput(tx, inputIndexCopy, txout, txData, input, flags));
        }
        public static async Task <ITestChainContext> CreatePosAsync(Network network, Script scriptPubKey, string dataDir, bool requireStandard = true)
        {
            var nodeSettings = new NodeSettings(network, args: new string[] { $"-datadir={dataDir}" });

            ILoggerFactory    loggerFactory    = nodeSettings.LoggerFactory;
            IDateTimeProvider dateTimeProvider = DateTimeProvider.Default;

            network.Consensus.Options = new ConsensusOptions();

            var consensusRulesContainer = new ConsensusRulesContainer();

            foreach (var ruleType in network.Consensus.ConsensusRules.HeaderValidationRules)
            {
                // Don't check PoW of a header in this test.
                if (ruleType == typeof(CheckDifficultyPowRule))
                {
                    continue;
                }

                consensusRulesContainer.HeaderValidationRules.Add(Activator.CreateInstance(ruleType) as HeaderValidationConsensusRule);
            }
            foreach (Type ruleType in network.Consensus.ConsensusRules.FullValidationRules)
            {
                consensusRulesContainer.FullValidationRules.Add(Activator.CreateInstance(ruleType) as FullValidationConsensusRule);
            }
            foreach (Type ruleType in network.Consensus.ConsensusRules.PartialValidationRules)
            {
                consensusRulesContainer.PartialValidationRules.Add(Activator.CreateInstance(ruleType) as PartialValidationConsensusRule);
            }

            var consensusSettings = new ConsensusSettings(nodeSettings);
            var chain             = new ChainIndexer(network);
            var inMemoryCoinView  = new InMemoryCoinView(new HashHeightPair(chain.Tip));

            var chainState  = new ChainState();
            var deployments = new NodeDeployments(network, chain);

            var asyncProvider = new AsyncProvider(loggerFactory, new Mock <ISignals>().Object);

            var stakeChain = new StakeChainStore(network, chain, null, loggerFactory);
            ConsensusRuleEngine consensusRules = new PosConsensusRuleEngine(network, loggerFactory, dateTimeProvider, chain, deployments, consensusSettings, new Checkpoints(),
                                                                            inMemoryCoinView, stakeChain, new StakeValidator(network, stakeChain, chain, inMemoryCoinView, loggerFactory), chainState, new InvalidBlockHashStore(dateTimeProvider),
                                                                            new NodeStats(dateTimeProvider, loggerFactory), new RewindDataIndexCache(dateTimeProvider, network, new FinalizedBlockInfoRepository(new HashHeightPair()), new Checkpoints()), asyncProvider, consensusRulesContainer).SetupRulesEngineParent();

            ConsensusManager consensus = ConsensusManagerHelper.CreateConsensusManager(network, dataDir, chainState, chainIndexer: chain, consensusRules: consensusRules, inMemoryCoinView: inMemoryCoinView);

            var genesis = new ChainedHeader(network.GetGenesis().Header, network.GenesisHash, 0);

            chainState.BlockStoreTip = genesis;
            await consensus.InitializeAsync(genesis).ConfigureAwait(false);

            var mempoolSettings = new MempoolSettings(nodeSettings)
            {
                RequireStandard = requireStandard
            };
            var blockPolicyEstimator = new BlockPolicyEstimator(mempoolSettings, loggerFactory, nodeSettings);
            var mempool     = new TxMempool(dateTimeProvider, blockPolicyEstimator, loggerFactory, nodeSettings);
            var mempoolLock = new MempoolSchedulerLock();

            // The mempool rule constructors aren't parameterless, so we have to manually inject the dependencies for every rule
            var mempoolRules = new List <MempoolRule>
            {
                new CheckConflictsMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new StraxCoinViewMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CreateMempoolEntryMempoolRule(network, mempool, mempoolSettings, chain, consensusRules, loggerFactory),
                new CheckSigOpsMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new StraxTransactionFeeMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckRateLimitMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckAncestorsMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckReplacementMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckAllInputsMempoolRule(network, mempool, mempoolSettings, chain, consensusRules, deployments, loggerFactory),
                new CheckTxOutDustRule(network, mempool, mempoolSettings, chain, loggerFactory),
            };

            // We also have to check that the manually instantiated rules match the ones in the network, or the test isn't valid
            for (int i = 0; i < network.Consensus.MempoolRules.Count; i++)
            {
                if (network.Consensus.MempoolRules[i] != mempoolRules[i].GetType())
                {
                    throw new Exception("Mempool rule type mismatch");
                }
            }

            var nodeDeployments = new NodeDeployments(network, chain);

            var mempoolValidator = new MempoolValidator(mempool, mempoolLock, dateTimeProvider, mempoolSettings, chain, inMemoryCoinView, loggerFactory, nodeSettings, consensusRules, mempoolRules, new Signals.Signals(loggerFactory, null), nodeDeployments);

            var            blocks = new List <Block>();
            var            srcTxs = new List <Transaction>();
            DateTimeOffset now    = DateTimeOffset.UtcNow;

            for (int i = 0; i < 50; i++)
            {
                uint  nonce = 0;
                Block block = network.CreateBlock();
                block.Header.HashPrevBlock = chain.Tip.HashBlock;
                block.Header.Bits          = block.Header.GetWorkRequired(network, chain.Tip);
                block.Header.UpdateTime(now, network, chain.Tip);

                Transaction coinbase = network.CreateTransaction();
                coinbase.AddInput(TxIn.CreateCoinbase(chain.Height + 1));
                coinbase.AddOutput(new TxOut(network.Consensus.ProofOfWorkReward, scriptPubKey));
                block.AddTransaction(coinbase);
                block.UpdateMerkleRoot();
                while (!block.CheckProofOfWork())
                {
                    block.Header.Nonce = ++nonce;
                }
                block.Header.PrecomputeHash();
                blocks.Add(block);
                chain.SetTip(block.Header);
                srcTxs.Add(block.Transactions[0]);

                inMemoryCoinView.SaveChanges(new List <UnspentOutput>()
                {
                    new UnspentOutput(new OutPoint(block.Transactions[0], 0), new Coins((uint)(i + 1), block.Transactions[0].Outputs.First(), block.Transactions[0].IsCoinBase))
                }, new HashHeightPair(chain.Tip.Previous), new HashHeightPair(chain.Tip));
            }

            return(new TestChainContext {
                MempoolValidator = mempoolValidator, MempoolSettings = mempoolSettings, ChainIndexer = chain, SrcTxs = srcTxs
            });
        }
        public List <uint256> GenerateBlocks(ReserveScript reserveScript, int generate, int maxTries, bool keepScript)
        {
            // temporary code to mine blocks while doing some simulations
            // this will be refactored to have the same logic as core with regards to
            // selecting and sorting transactions from the mempool.

            if (fullNode.Chain.Tip != fullNode.ConsensusLoop.Tip)
            {
                return(Enumerable.Empty <uint256>().ToList());
            }

            List <Block> blocks = new List <Block>();

            for (int i = 0; i < generate; i++)
            {
                uint  nonce = 0;
                Block block = new Block();
                block.Header.HashPrevBlock = fullNode.Chain.Tip.HashBlock;
                //block.Header.Bits = GetWorkRequired(fullNode.Network.Consensus,new ChainedBlock(block.Header, (uint256) null, fullNode.Chain.Tip));
                block.Header.Bits = block.Header.GetWorkRequired(fullNode.Network, fullNode.Chain.Tip);
                block.Header.UpdateTime(dateTimeProvider.GetTimeOffset(), fullNode.Network, fullNode.Chain.Tip);
                var coinbase = new Transaction();
                coinbase.AddInput(TxIn.CreateCoinbase(fullNode.Chain.Height + 1));
                coinbase.AddOutput(new TxOut(fullNode.Network.GetReward(fullNode.Chain.Height + 1), reserveScript.reserveSfullNodecript));
                block.AddTransaction(coinbase);
                //if (passedTransactions?.Any() ?? false)
                //{
                //	passedTransactions = Reorder(passedTransactions);
                //	block.Transactions.AddRange(passedTransactions);
                //}
                block.UpdateMerkleRoot();
                var retry = 0;
                while (!block.CheckProofOfWork() && !fullNode.IsDisposed && ++retry < maxTries)
                {
                    block.Header.Nonce = ++nonce;
                }
                if (fullNode.IsDisposed || retry >= maxTries)
                {
                    return(blocks.Select(b => b.GetHash()).ToList());
                }
                if (block.Header.HashPrevBlock != fullNode.Chain.Tip.HashBlock)
                {
                    i--;
                    continue;                     // a new block was found continue to look
                }
                blocks.Add(block);
                var newChain = new ChainedBlock(block.Header, block.GetHash(), fullNode.Chain.Tip);
                fullNode.Chain.SetTip(newChain);

                var blockResult = new BlockResult {
                    Block = block
                };
                fullNode.ConsensusLoop.AcceptBlock(blockResult);

                if (blockResult.ChainedBlock == null)
                {
                    break;                     //reorg
                }
                // similar logic to what's in the full node code
                if (blockResult.Error == null)
                {
                    fullNode.ChainBehaviorState.HighestValidatedPoW = fullNode.ConsensusLoop.Tip;
                    //if (fullNode.Chain.Tip.HashBlock == blockResult.ChainedBlock.HashBlock)
                    //{
                    //	var unused = cache.FlushAsync();
                    //}
                    fullNode.Signals.Blocks.Broadcast(block);
                }

                // ensure the block is written to disk
                retry = 0;
                while (++retry < maxTries && this.fullNode.BlockStoreManager.BlockRepository.GetAsync(blockResult.ChainedBlock.HashBlock).GetAwaiter().GetResult() == null)
                {
                    Thread.Sleep(100);
                }
                if (retry >= maxTries)
                {
                    return(blocks.Select(b => b.GetHash()).ToList());
                }
            }

            return(blocks.Select(b => b.GetHash()).ToList());
        }
        /// <summary>
        /// Creates a cold staking withdrawal <see cref="Transaction"/>.
        /// </summary>
        /// <remarks>
        /// Cold staking withdrawal is performed on the wallet that is in the role of the cold staking cold wallet.
        /// </remarks>
        /// <param name="walletTransactionHandler">The wallet transaction handler used to build the transaction.</param>
        /// <param name="receivingAddress">The address that will receive the withdrawal.</param>
        /// <param name="walletName">The name of the wallet in the role of cold wallet.</param>
        /// <param name="walletPassword">The wallet password.</param>
        /// <param name="amount">The amount to remove from cold staking.</param>
        /// <param name="feeAmount">The fee to pay for cold staking transaction withdrawal.</param>
        /// <returns>The <see cref="Transaction"/> for cold staking withdrawal.</returns>
        /// <exception cref="WalletException">Thrown if the receiving address is in a cold staking account in this wallet.</exception>
        /// <exception cref="ArgumentNullException">Thrown if the receiving address is invalid.</exception>
        internal Transaction GetColdStakingWithdrawalTransaction(IWalletTransactionHandler walletTransactionHandler, string receivingAddress,
                                                                 string walletName, string walletPassword, Money amount, Money feeAmount)
        {
            Guard.NotEmpty(receivingAddress, nameof(receivingAddress));
            Guard.NotEmpty(walletName, nameof(walletName));
            Guard.NotNull(amount, nameof(amount));
            Guard.NotNull(feeAmount, nameof(feeAmount));

            this.logger.LogTrace("({0}:'{1}',{2}:'{3}',{4}:'{5}',{6}:'{7}'",
                                 nameof(receivingAddress), receivingAddress,
                                 nameof(walletName), walletName,
                                 nameof(amount), amount,
                                 nameof(feeAmount), feeAmount
                                 );

            Wallet.Wallet wallet = this.GetWalletByName(walletName);

            // Get the cold staking account.
            HdAccount coldAccount = this.GetColdStakingAccount(wallet, true);

            if (coldAccount == null)
            {
                this.logger.LogTrace("(-)[COLDSTAKE_ACCOUNT_DOES_NOT_EXIST]");
                throw new WalletException("The cold wallet account does not exist.");
            }

            // Prevent reusing cold stake addresses as regular withdrawal addresses.
            if (coldAccount.ExternalAddresses.Concat(coldAccount.InternalAddresses).Select(a => a.Address.ToString()).Contains(receivingAddress))
            {
                this.logger.LogTrace("(-)[COLDSTAKE_INVALID_COLD_WALLET_ADDRESS_USAGE]");
                throw new WalletException("You can't send the money to a cold staking cold wallet account.");
            }

            HdAccount hotAccount = this.GetColdStakingAccount(wallet, false);

            if (hotAccount != null && hotAccount.ExternalAddresses.Concat(hotAccount.InternalAddresses).Select(a => a.Address.ToString()).Contains(receivingAddress))
            {
                this.logger.LogTrace("(-)[COLDSTAKE_INVALID_HOT_WALLET_ADDRESS_USAGE]");
                throw new WalletException("You can't send the money to a cold staking hot wallet account.");
            }

            // Send the money to the receiving address.
            Script destination = BitcoinAddress.Create(receivingAddress, wallet.Network).ScriptPubKey;

            // Create the transaction build context (used in BuildTransaction).
            var accountReference = new WalletAccountReference(walletName, coldAccount.Name);
            var context          = new TransactionBuildContext(wallet.Network)
            {
                AccountReference = accountReference,
                // Specify a dummy change address to prevent a change (internal) address from being created.
                // Will be changed after the transacton is built and before it is signed.
                ChangeAddress    = coldAccount.ExternalAddresses.First(),
                TransactionFee   = feeAmount,
                MinConfirmations = 0,
                Shuffle          = false,
                Sign             = false,
                Recipients       = new[] { new Recipient {
                                               Amount = amount, ScriptPubKey = destination
                                           } }.ToList()
            };

            // Register the cold staking builder extension with the transaction builder.
            context.TransactionBuilder.Extensions.Add(new ColdStakingBuilderExtension(false));

            // Avoid script errors due to missing scriptSig.
            context.TransactionBuilder.StandardTransactionPolicy.ScriptVerify = null;

            // Build the transaction according to the settings recorded in the context.
            Transaction transaction = walletTransactionHandler.BuildTransaction(context);

            // Map OutPoint to UnspentOutputReference.
            Dictionary <OutPoint, UnspentOutputReference> mapOutPointToUnspentOutput = this.GetSpendableTransactionsInAccount(accountReference)
                                                                                       .ToDictionary(unspent => unspent.ToOutPoint(), unspent => unspent);

            // Set the cold staking scriptPubKey on the change output.
            TxOut changeOutput = transaction.Outputs.SingleOrDefault(output => (output.ScriptPubKey != destination) && (output.Value != 0));

            if (changeOutput != null)
            {
                // Find the largest input.
                TxIn largestInput = transaction.Inputs.OrderByDescending(input => mapOutPointToUnspentOutput[input.PrevOut].Transaction.Amount).Take(1).Single();

                // Set the scriptPubKey of the change output to the scriptPubKey of the largest input.
                changeOutput.ScriptPubKey = mapOutPointToUnspentOutput[largestInput.PrevOut].Transaction.ScriptPubKey;
            }

            // Add keys for signing inputs. This takes time so only add keys for distinct addresses.
            foreach (HdAddress address in transaction.Inputs.Select(i => mapOutPointToUnspentOutput[i.PrevOut].Address).Distinct())
            {
                context.TransactionBuilder.AddKeys(wallet.GetExtendedPrivateKeyForAddress(walletPassword, address));
            }

            // Sign the transaction.
            context.TransactionBuilder.SignTransactionInPlace(transaction);

            this.logger.LogTrace("(-):'{0}'", transaction.GetHash());
            return(transaction);
        }
        /// <summary>
        /// Verify that an input may be validly spent as part of the given transaction in the given block.
        /// </summary>
        /// <param name="tx">Transaction to check.</param>
        /// <param name="inputIndexCopy">Index of the input to check.</param>
        /// <param name="txout">Output the input is spending.</param>
        /// <param name="txData">Transaction data for the transaction being checked.</param>
        /// <param name="input">Input to check.</param>
        /// <param name="flags">Deployment flags</param>
        /// <returns>Whether the input is valid.</returns>
        protected virtual bool CheckInput(Transaction tx, int inputIndexCopy, TxOut txout, PrecomputedTransactionData txData, TxIn input, DeploymentFlags flags)
        {
            var checker = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
            var ctx     = new ScriptEvaluationContext(this.Parent.Network);

            ctx.ScriptVerify = flags.ScriptFlags;
            bool verifyScriptResult = ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker);

            if (verifyScriptResult == false)
            {
                this.Logger.LogTrace("Verify script for transaction '{0}' failed, ScriptSig = '{1}', ScriptPubKey = '{2}', script evaluation error = '{3}'", tx.GetHash(), input.ScriptSig, txout.ScriptPubKey, ctx.Error);
            }

            return(verifyScriptResult);
        }
        public TxOut GetOutputFor(TxIn input)
        {
            Coins coins = GetCoins(input.PrevOut.Hash);

            return(coins.TryGetOutput(input.PrevOut.N));
        }
 public RPCTransactionInput(TxIn txin)
 {
     TxId      = txin.PrevOut.Hash;
     vout      = txin.PrevOut.N;
     nSequence = txin.Sequence;
 }
        private static Transaction CreateTransactionThatSpendCoinstake(StratisRegTest network, CoreNode minerA, CoreNode minerB, TxIn coinstake, Transaction txWithBigPremine)
        {
            Transaction txThatSpendCoinstake = network.CreateTransaction();

            txThatSpendCoinstake.AddInput(new TxIn(new OutPoint(txWithBigPremine, 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(minerA.MinerSecret.PubKey)));
            txThatSpendCoinstake.AddOutput(new TxOut
            {
                Value        = txWithBigPremine.Outputs[0].Value - new Money(1, MoneyUnit.BTC),
                ScriptPubKey = minerB.MinerHDAddress.ScriptPubKey
            });

            var dateTimeProvider = minerA.FullNode.NodeService <IDateTimeProvider>();

            if (txThatSpendCoinstake is IPosTransactionWithTime posTrx)
            {
                posTrx.Time = (uint)dateTimeProvider.GetAdjustedTimeAsUnixTimestamp();
            }

            Coin         spentCoin = new Coin(txWithBigPremine, 0);
            List <ICoin> coins     = new List <ICoin> {
                spentCoin
            };

            txThatSpendCoinstake.Sign(minerA.FullNode.Network, minerA.MinerSecret, coins[0]);

            return(txThatSpendCoinstake);
        }
Exemple #28
0
        public virtual void ExecuteBlock(ContextInformation context, TaskScheduler taskScheduler)
        {
            this.logger.LogTrace("()");

            Block            block = context.BlockValidationContext.Block;
            ChainedBlock     index = context.BlockValidationContext.ChainedBlock;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = context.Set;

            this.PerformanceCounter.AddProcessedBlocks(1);
            taskScheduler = taskScheduler ?? TaskScheduler.Default;

            if (!context.BlockValidationContext.SkipValidation)
            {
                if (flags.EnforceBIP30)
                {
                    foreach (Transaction tx in block.Transactions)
                    {
                        UnspentOutputs coins = view.AccessCoins(tx.GetHash());
                        if ((coins != null) && !coins.IsPrunable)
                        {
                            this.logger.LogTrace("(-)[BAD_TX_BIP_30]");
                            ConsensusErrors.BadTransactionBIP30.Throw();
                        }
                    }
                }
            }
            else
            {
                this.logger.LogTrace("BIP30 validation skipped for checkpointed block at height {0}.", index.Height);
            }

            long  nSigOpsCost = 0;
            Money nFees       = Money.Zero;
            List <Task <bool> > checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                this.PerformanceCounter.AddProcessedTransactions(1);
                Transaction tx = block.Transactions[txIndex];
                if (!context.BlockValidationContext.SkipValidation)
                {
                    if (!tx.IsCoinBase && (!context.IsPoS || (context.IsPoS && !tx.IsCoinStake)))
                    {
                        int[] prevheights;

                        if (!view.HaveInputs(tx))
                        {
                            this.logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                            ConsensusErrors.BadTransactionMissingInput.Throw();
                        }

                        prevheights = new int[tx.Inputs.Count];
                        // Check that transaction is BIP68 final.
                        // BIP68 lock checks (as opposed to nLockTime checks) must
                        // be in ConnectBlock because they require the UTXO set.
                        for (int j = 0; j < tx.Inputs.Count; j++)
                        {
                            prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                        }

                        if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                        {
                            this.logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                            ConsensusErrors.BadTransactionNonFinal.Throw();
                        }
                    }

                    // GetTransactionSigOpCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    nSigOpsCost += this.GetTransactionSigOpCost(tx, view, flags);
                    if (nSigOpsCost > this.consensusOptions.MaxBlockSigopsCost)
                    {
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    // TODO: Simplify this condition.
                    if (!tx.IsCoinBase && (!context.IsPoS || (context.IsPoS && !tx.IsCoinStake)))
                    {
                        this.CheckInputs(tx, view, index.Height);
                        nFees += view.GetValueIn(tx) - tx.TotalOut;
                        Transaction localTx = tx;
                        PrecomputedTransactionData txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            this.PerformanceCounter.AddProcessedInputs(1);
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() =>
                            {
                                if (this.UseConsensusLib)
                                {
                                    Script.BitcoinConsensusError error;
                                    return(Script.VerifyScriptConsensus(txout.ScriptPubKey, tx, (uint)inputIndexCopy, flags.ScriptFlags, out error));
                                }
                                else
                                {
                                    var checker      = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
                                    var ctx          = new ScriptEvaluationContext();
                                    ctx.ScriptVerify = flags.ScriptFlags;
                                    return(ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker));
                                }
                            });
                            checkInput.Start(taskScheduler);
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.BlockValidationContext.SkipValidation)
            {
                this.CheckBlockReward(context, nFees, index, block);

                bool passed = checkInputs.All(c => c.GetAwaiter().GetResult());
                if (!passed)
                {
                    this.logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }

            this.logger.LogTrace("(-)");
        }
        /// <inheritdoc />
        public override async Task RunAsync(RuleContext context)
        {
            Block            block = context.ValidationContext.BlockToValidate;
            ChainedHeader    index = context.ValidationContext.ChainedHeaderToValidate;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = (context as UtxoRuleContext).UnspentOutputSet;

            long  sigOpsCost  = 0;
            Money fees        = Money.Zero;
            var   checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                Transaction tx = block.Transactions[txIndex];

                if (!context.SkipValidation)
                {
                    if (!this.IsProtocolTransaction(tx))
                    {
                        if (!view.HaveInputs(tx))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                            ConsensusErrors.BadTransactionMissingInput.Throw();
                        }

                        var prevheights = new int[tx.Inputs.Count];
                        // Check that transaction is BIP68 final.
                        // BIP68 lock checks (as opposed to nLockTime checks) must
                        // be in ConnectBlock because they require the UTXO set.
                        for (int j = 0; j < tx.Inputs.Count; j++)
                        {
                            prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                        }

                        if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                            ConsensusErrors.BadTransactionNonFinal.Throw();
                        }
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.ConsensusOptions.MaxBlockSigopsCost)
                    {
                        this.Logger.LogTrace("(-)[BAD_BLOCK_SIG_OPS]");
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    if (!this.IsProtocolTransaction(tx))
                    {
                        this.CheckInputs(tx, view, index.Height);
                        fees += view.GetValueIn(tx) - tx.TotalOut;
                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() => this.CheckInput(tx, inputIndexCopy, txout, txData, input, flags));
                            checkInput.Start();
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                foreach (Task <bool> checkInput in checkInputs)
                {
                    if (await checkInput.ConfigureAwait(false))
                    {
                        continue;
                    }

                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }
        }
        public async Task <WalletCreateFundedPSBTResponse> WalletCreateFundedPSBTAsync(
            TxIn[] inputs,
            Tuple <Dictionary <BitcoinAddress, Money>, Dictionary <string, string> > outputs,
            LockTime locktime = default(LockTime),
            FundRawTransactionOptions options = null,
            bool bip32derivs = false
            )
        {
            var values = new object[] { };

            if (inputs == null)
            {
                inputs = new TxIn[] { }
            }
            ;
            if (outputs == null)
            {
                throw new ArgumentNullException(nameof(outputs));
            }

            var rpcInputs = inputs.Select(i => i.ToRPCInputs()).ToArray();

            var outputToSend = new JObject {
            };

            if (outputs.Item1 != null)
            {
                foreach (var kv in outputs.Item1)
                {
                    outputToSend.Add(kv.Key.ToString(), kv.Value.ToUnit(MoneyUnit.BTC));
                }
            }
            if (outputs.Item2 != null)
            {
                foreach (var kv in outputs.Item2)
                {
                    outputToSend.Add(kv.Key, kv.Value);
                }
            }
            JObject jOptions;

            if (options != null)
            {
                jOptions = FundRawTransactionOptionsToJson(options);
            }
            else
            {
                jOptions = (JObject)"";
            }
            RPCResponse response = await SendCommandAsync(
                "walletcreatefundedpsbt",
                rpcInputs,
                outputToSend,
                locktime.Value,
                jOptions,
                bip32derivs).ConfigureAwait(false);

            var result    = (JObject)response.Result;
            var psbt      = PSBT.Parse(result.Property("psbt").Value.Value <string>(), Network.Main);
            var fee       = Money.Coins(result.Property("fee").Value.Value <decimal>());
            var changePos = result.Property("changepos").Value.Value <int>();
            var tmp       = changePos == -1 ? (int?)null : (int?)changePos;

            return(new WalletCreateFundedPSBTResponse {
                PSBT = psbt, Fee = fee, ChangePos = tmp
            });
        }
Exemple #31
0
        public EntityWatchRepositoryTests()
        {
            var network = ZcoinNetworks.Instance.Regtest;

            this.block1 = Block.CreateBlock(network);
            this.block2 = Block.CreateBlock(network);

            this.tx1 = Transaction.Create(network);
            this.tx1.Inputs.Add(TxIn.CreateCoinbase(102));
            this.tx1.Outputs.Add(Money.Coins(30), TestAddress.Regtest1);
            this.tx1.Outputs.Add(Money.Coins(10), TestAddress.Regtest2);

            this.tx2 = Transaction.Create(network);
            this.tx2.Inputs.Add(TxIn.CreateCoinbase(103));
            this.tx2.Outputs.Add(Money.Coins(40), TestAddress.Regtest2);

            this.tx3 = Transaction.Create(network);
            this.tx3.Inputs.Add(this.tx1, 0).ScriptSig = new Script(OpcodeType.OP_0);
            this.tx3.Outputs.Add(Money.Cents(1), TestAddress.Regtest2);

            this.tx4 = Transaction.Create(network);
            this.tx4.Inputs.Add(this.tx1, 1).ScriptSig = new Script(OpcodeType.OP_0);
            this.tx4.Outputs.Add(Money.Cents(1), TestAddress.Regtest2);

            this.block1.AddTransaction(this.tx1);
            this.block2.AddTransaction(this.tx2);
            this.block2.AddTransaction(this.tx3);
            this.block2.AddTransaction(this.tx4);

            this.block1.UpdateMerkleRoot();
            this.block2.UpdateMerkleRoot();

            this.address1 = new ReceivingAddress(
                Guid.NewGuid(),
                TestAddress.Regtest1,
                true,
                new Collection <ReceivingAddressReservation>());

            this.address2 = new ReceivingAddress(
                Guid.NewGuid(),
                TestAddress.Regtest2,
                true,
                new Collection <ReceivingAddressReservation>());

            this.reservation1 = new ReceivingAddressReservation(Guid.NewGuid(), this.address1, DateTime.Now, null);
            this.reservation2 = new ReceivingAddressReservation(Guid.NewGuid(), this.address2, DateTime.Now, null);

            this.rule1 = new Rule(
                new PropertyId(3),
                this.reservation1,
                new PropertyAmount(100),
                6,
                TimeSpan.FromHours(1),
                new TokenReceivingCallback(
                    new Callback(
                        Guid.NewGuid(),
                        IPAddress.Parse("192.168.1.2"),
                        DateTime.Now,
                        false,
                        new Uri("http://localhost/a")),
                    "timeout"));

            this.rule2 = new Rule(
                new PropertyId(4),
                this.reservation2,
                new PropertyAmount(40),
                3,
                TimeSpan.FromMinutes(30),
                null);

            this.watch1 = new DomainModel(
                this.rule1,
                this.block1.GetHash(),
                this.tx1.GetHash(),
                this.rule1.AddressReservation.Address.Address,
                new PropertyAmount(100));

            this.watch2 = new DomainModel(
                this.rule2,
                this.block1.GetHash(),
                this.tx1.GetHash(),
                this.rule2.AddressReservation.Address.Address,
                new PropertyAmount(10));

            this.watch3 = new DomainModel(
                this.rule2,
                this.block2.GetHash(),
                this.tx2.GetHash(),
                this.rule2.AddressReservation.Address.Address,
                new PropertyAmount(10));

            this.watch4 = new DomainModel(
                this.rule2,
                this.block2.GetHash(),
                this.tx3.GetHash(),
                this.rule2.AddressReservation.Address.Address,
                new PropertyAmount(10));

            this.watch5 = new DomainModel(
                this.rule2,
                this.block2.GetHash(),
                this.tx4.GetHash(),
                this.rule2.AddressReservation.Address.Address,
                new PropertyAmount(10));

            this.db = new TestMainDatabaseFactory();

            try
            {
                this.rules = new Mock <IRuleRepository>();
                this.rules
                .Setup(r => r.GetAsync(this.rule1.Id, It.IsAny <CancellationToken>()))
                .ReturnsAsync(this.rule1);
                this.rules
                .Setup(r => r.GetAsync(this.rule2.Id, It.IsAny <CancellationToken>()))
                .ReturnsAsync(this.rule2);

                this.subject = new EntityWatchRepository(this.db, this.rules.Object);
            }
            catch
            {
                this.db.Dispose();
                throw;
            }
        }
Exemple #32
0
        public async Task PosCoinViewRuleFailsAsync()
        {
            var unspentOutputs = new Dictionary <OutPoint, UnspentOutput>();

            ConsensusManager consensusManager = await this.CreateConsensusManagerAsync(unspentOutputs);

            // The keys used by miner 1 and miner 2.
            var minerKey1 = new Key();
            var minerKey2 = new Key();

            // The scriptPubKeys (P2PK) of the miners.
            Script scriptPubKey1 = minerKey1.PubKey.ScriptPubKey;
            Script scriptPubKey2 = minerKey2.PubKey.ScriptPubKey;

            // Create the block that we want to validate.
            Block block = this.network.Consensus.ConsensusFactory.CreateBlock();

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

            transaction.Inputs.Add(TxIn.CreateCoinbase(this.ChainIndexer.Tip.Height + 1));
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            Assert.True(transaction.IsCoinBase);

            // Add first transaction to block.
            block.Transactions.Add(transaction);

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

            uint blockTime = (this.ChainIndexer.Tip.Header.Time + 60) & ~PosConsensusOptions.StakeTimestampMask;

            // Coins sent to miner 2.
            prevTransaction.Outputs.Add(new TxOut(Money.COIN * 5_000_000, scriptPubKey2));
            // Coins sent to miner 1.
            prevTransaction.Outputs.Add(new TxOut(Money.COIN * 10_000_000, scriptPubKey1));

            // Record the spendable outputs.
            unspentOutputs.Add(new OutPoint(prevTransaction, 0), new UnspentOutput(new OutPoint(prevTransaction, 0), new Coins(1, prevTransaction.Outputs[0], prevTransaction.IsCoinBase)));
            unspentOutputs.Add(new OutPoint(prevTransaction, 1), new UnspentOutput(new OutPoint(prevTransaction, 1), new Coins(1, prevTransaction.Outputs[1], prevTransaction.IsCoinBase)));

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

            coinstakeTransaction.Inputs.Add(new TxIn(new OutPoint(prevTransaction, 0)));
            coinstakeTransaction.Inputs.Add(new TxIn(new OutPoint(prevTransaction, 1)));

            // Coinstake marker.
            coinstakeTransaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));

            // We need to pay the Cirrus reward to the correct scriptPubKey to prevent failing that consensus rule.
            coinstakeTransaction.Outputs.Add(new TxOut(Money.COIN * 9, StraxCoinstakeRule.CirrusRewardScript));

            // Normal pay to public key that belongs to the second miner with value that
            // equals to the sum of the inputs.
            coinstakeTransaction.Outputs.Add(new TxOut(Money.COIN * 15_000_000, scriptPubKey2));

            // The second miner signs the first transaction input which requires minerKey2.
            // Miner 2 will not have minerKey1 so we leave the second ScriptSig empty/invalid.
            new TransactionBuilder(this.network)
            .AddKeys(minerKey2)
            .AddCoins(new Coin(new OutPoint(prevTransaction, 0), prevTransaction.Outputs[0]))
            .SignTransactionInPlace(coinstakeTransaction);

            Assert.True(coinstakeTransaction.IsCoinStake);

            // Add second transaction to block.
            block.Transactions.Add(coinstakeTransaction);

            // Finalize the block and add it to the chain.
            block.Header.HashPrevBlock = this.ChainIndexer.Tip.HashBlock;
            block.Header.Time          = blockTime;
            block.Header.Bits          = block.Header.GetWorkRequired(this.network, this.ChainIndexer.Tip);
            block.SetPrivatePropertyValue("BlockSize", 1L);
            block.UpdateMerkleRoot();
            Assert.True(BlockStake.IsProofOfStake(block));
            // Add a signature to the block.
            ECDSASignature signature = minerKey2.Sign(block.GetHash());

            (block as PosBlock).BlockSignature = new BlockSignature {
                Signature = signature.ToDER()
            };

            // Execute the rule and check the outcome against what is expected.
            ConsensusException error = await Assert.ThrowsAsync <ConsensusException>(async() => await consensusManager.BlockMinedAsync(block));

            Assert.Equal(ConsensusErrors.BadTransactionScriptError.Message, error.Message);
        }
Exemple #33
0
        public static async Task <ColoredTransaction> FetchColorsAsync(uint256 txId, Transaction tx, IColoredTransactionRepository repo)
        {
            if (repo == null)
            {
                throw new ArgumentNullException("repo");
            }
            if (txId == null)
            {
                if (tx == null)
                {
                    throw new ArgumentException("txId or tx should be different of null");
                }
                txId = tx.GetHash();
            }
            //The following code is to prevent recursion of FetchColors that would fire a StackOverflow if the origin of traded asset were deep in the transaction dependency tree
            ColoredTransaction colored = await repo.GetAsync(txId).ConfigureAwait(false);

            if (colored != null)
            {
                return(colored);
            }

            var frames   = new Stack <ColoredFrame>();
            var coloreds = new Stack <ColoredTransaction>();

            frames.Push(new ColoredFrame()
            {
                TransactionId = txId,
                Transaction   = tx
            });
            while (frames.Count != 0)
            {
                ColoredFrame frame = frames.Pop();
                colored = frame.PreviousTransactions != null ? null : await repo.GetAsync(frame.TransactionId).ConfigureAwait(false); //Already known

                if (colored != null)
                {
                    coloreds.Push(colored);
                    continue;
                }
                frame.Transaction = frame.Transaction ?? await repo.Transactions.GetAsync(frame.TransactionId).ConfigureAwait(false);

                if (frame.Transaction == null)
                {
                    throw new TransactionNotFoundException("Transaction " + frame.TransactionId + " not found in transaction repository", frame.TransactionId);
                }
                if (frame.PreviousTransactions == null)
                {
                    if (frame.Transaction.IsCoinBase ||
                        (!frame.Transaction.HasValidColoredMarker() &&
                         frame.TransactionId != txId)) //We care about destroyed asset, if this is the requested transaction
                    {
                        coloreds.Push(new ColoredTransaction());
                        continue;
                    }
                    frame.PreviousTransactions = new ColoredTransaction[frame.Transaction.Inputs.Count];
                    await BulkLoadIfCached(frame.Transaction, repo).ConfigureAwait(false);

                    frames.Push(frame);
                    for (int i = 0; i < frame.Transaction.Inputs.Count; i++)
                    {
                        frames.Push(new ColoredFrame()
                        {
                            TransactionId = frame.Transaction.Inputs[i].PrevOut.Hash
                        });
                    }
                    frame.Transaction = frame.TransactionId == txId ? frame.Transaction : null; //Do not waste memory, will refetch later
                    continue;
                }
                else
                {
                    for (int i = 0; i < frame.Transaction.Inputs.Count; i++)
                    {
                        frame.PreviousTransactions[i] = coloreds.Pop();
                    }
                }

                Script issuanceScriptPubkey = null;
                if (HasIssuance(frame.Transaction))
                {
                    TxIn        txIn     = frame.Transaction.Inputs[0];
                    Transaction previous = await repo.Transactions.GetAsync(txIn.PrevOut.Hash).ConfigureAwait(false);

                    if (previous == null)
                    {
                        throw new TransactionNotFoundException("An open asset transaction is issuing assets, but it needs a parent transaction in the TransactionRepository to know the address of the issued asset (missing : " + txIn.PrevOut.Hash + ")", txIn.PrevOut.Hash);
                    }
                    if (txIn.PrevOut.N < previous.Outputs.Count)
                    {
                        issuanceScriptPubkey = previous.Outputs[txIn.PrevOut.N].ScriptPubKey;
                    }
                }

                var spentCoins = new List <ColoredCoin>();
                for (int i = 0; i < frame.Transaction.Inputs.Count; i++)
                {
                    TxIn         txIn  = frame.Transaction.Inputs[i];
                    ColoredEntry entry = frame.PreviousTransactions[i].GetColoredEntry(txIn.PrevOut.N);
                    if (entry != null)
                    {
                        spentCoins.Add(new ColoredCoin(entry.Asset, new Coin(txIn.PrevOut, new TxOut())));
                    }
                }
                colored = new ColoredTransaction(frame.TransactionId, frame.Transaction, spentCoins.ToArray(), issuanceScriptPubkey);
                coloreds.Push(colored);
                await repo.PutAsync(frame.TransactionId, colored).ConfigureAwait(false);
            }
            if (coloreds.Count != 1)
            {
                throw new InvalidOperationException("Colored stack length != 1, this is a NBitcoin bug, please contact us.");
            }
            return(coloreds.Pop());
        }
Exemple #34
0
		void ReplaceRedeemScript(TxIn input, Script redeemScript)
		{
			ScriptEvaluationContext ctx = new ScriptEvaluationContext();
			ctx.ScriptVerify = ScriptVerify.StrictEnc;
			ctx.EvalScript(input.ScriptSig, new Transaction(), 0);
			var stack = ctx.Stack;
			Assert.True(stack.Count > 0);
			stack.Pop();
			stack.Push(redeemScript.ToBytes());
			input.ScriptSig = PushAll(stack);
		}
Exemple #35
0
        public ColoredTransaction(uint256 txId, Transaction tx, ColoredCoin[] spentCoins, Script issuanceScriptPubkey)
            : this()
        {
            if (tx == null)
            {
                throw new ArgumentNullException("tx");
            }
            if (spentCoins == null)
            {
                throw new ArgumentNullException("spentCoins");
            }
            if (tx.IsCoinBase || tx.Inputs.Count == 0)
            {
                return;
            }
            txId = txId ?? tx.GetHash();

            var previousAssetQueue = new Queue <ColoredEntry>();

            for (uint i = 0; i < tx.Inputs.Count; i++)
            {
                TxIn        txin      = tx.Inputs[i];
                ColoredCoin prevAsset = spentCoins.FirstOrDefault(s => s.Outpoint == txin.PrevOut);
                if (prevAsset != null)
                {
                    var input = new ColoredEntry()
                    {
                        Index = i,
                        Asset = prevAsset.Amount
                    };
                    previousAssetQueue.Enqueue(input);
                    this.Inputs.Add(input);
                }
            }

            uint        markerPos = 0;
            ColorMarker marker    = ColorMarker.Get(tx, out markerPos);

            if (marker == null)
            {
                return;
            }

            this.Marker = marker;
            if (!marker.HasValidQuantitiesCount(tx))
            {
                return;
            }

            AssetId issuedAsset = null;

            for (uint i = 0; i < markerPos; i++)
            {
                var entry = new ColoredEntry();
                entry.Index = i;
                entry.Asset = new AssetMoney(entry.Asset.Id, i >= marker.Quantities.Length ? 0 : marker.Quantities[i]);
                if (entry.Asset.Quantity == 0)
                {
                    continue;
                }

                if (issuedAsset == null)
                {
                    TxIn txIn = tx.Inputs.FirstOrDefault();
                    if (txIn == null)
                    {
                        continue;
                    }
                    if (issuanceScriptPubkey == null)
                    {
                        throw new ArgumentException("The transaction has an issuance detected, but issuanceScriptPubkey is null.", "issuanceScriptPubkey");
                    }
                    issuedAsset = issuanceScriptPubkey.Hash.ToAssetId();
                }
                entry.Asset = new AssetMoney(issuedAsset, entry.Asset.Quantity);
                this.Issuances.Add(entry);
            }

            long used = 0;

            for (uint i = markerPos + 1; i < tx.Outputs.Count; i++)
            {
                var entry = new ColoredEntry();
                entry.Index = i;
                //If there are less items in the  asset quantity list  than the number of colorable outputs (all the outputs except the marker output), the outputs in excess receive an asset quantity of zero.
                entry.Asset = new AssetMoney(entry.Asset.Id, (i - 1) >= marker.Quantities.Length ? 0 : marker.Quantities[i - 1]);
                if (entry.Asset.Quantity == 0)
                {
                    continue;
                }

                //If there are less asset units in the input sequence than in the output sequence, the transaction is considered invalid and all outputs are uncolored.
                if (previousAssetQueue.Count == 0)
                {
                    this.Transfers.Clear();
                    this.Issuances.Clear();
                    return;
                }
                entry.Asset = new AssetMoney(previousAssetQueue.Peek().Asset.Id, entry.Asset.Quantity);
                long remaining = entry.Asset.Quantity;
                while (remaining != 0)
                {
                    if (previousAssetQueue.Count == 0 || previousAssetQueue.Peek().Asset.Id != entry.Asset.Id)
                    {
                        this.Transfers.Clear();
                        this.Issuances.Clear();
                        return;
                    }
                    long assertPart = Math.Min(previousAssetQueue.Peek().Asset.Quantity - used, remaining);
                    remaining = remaining - assertPart;
                    used     += assertPart;
                    if (used == previousAssetQueue.Peek().Asset.Quantity)
                    {
                        previousAssetQueue.Dequeue();
                        used = 0;
                    }
                }

                this.Transfers.Add(entry);
            }
        }
Exemple #36
0
		public TxOut GetOutputFor(TxIn input)
		{
			Coins coins = GetCoins(input.PrevOut.Hash);
			if(!coins.IsAvailable(input.PrevOut.N))
			{
				return null;
			}
			return coins.Outputs[(int)input.PrevOut.N];
		}
        private void addOnlyInputToTransaction(Transaction t, TransactionOutPointWithValue prevOut, uint sequence)
        {
            TxIn input = new TxIn(prevOut.outpoint)
            {
                ScriptSig = new Script(Op.GetPushOp(0))
            };
            input.Sequence = sequence;
            t.AddInput(input);

            var hash = prevOut.scriptPubKey.SignatureHash(t, 0, SigHash.All);
            input.ScriptSig = new PayToPubkeyHashTemplate().GenerateScriptSig(new TransactionSignature(coinbaseOutKey.Sign(hash), SigHash.All),coinbaseOutKeyPubKey);
        }