예제 #1
0
            private void SerializeTxn(BitcoinStream stream)
            {
                var version = this.Version;

                stream.ReadWrite(ref version);

                // POS Timestamp
                var time = this.Time;

                stream.ReadWrite(ref time);

                TxInList vin = this.Inputs;

                stream.ReadWrite(ref vin);
                vin.Transaction = this;

                TxOutList vout = this.Outputs;

                stream.ReadWrite(ref vout);
                vout.Transaction = this;

                LockTime lockTime = this.LockTime;

                stream.ReadWriteStruct(ref lockTime);
            }
예제 #2
0
            private void DeserializeTxn(BitcoinStream stream)
            {
                UInt32 nVersionTemp = 0;

                stream.ReadWrite(ref nVersionTemp);

                // POS time stamp
                UInt32 nTimeTemp = 0;

                stream.ReadWrite(ref nTimeTemp);

                TxInList  vinTemp  = null;
                TxOutList voutTemp = null;

                // Try to read the vin.
                stream.ReadWrite(ref vinTemp);
                vinTemp.Transaction = this;
                // Assume a normal vout follows.
                stream.ReadWrite(ref voutTemp);
                voutTemp.Transaction = this;

                LockTime lockTimeTemp = LockTime.Zero;

                stream.ReadWriteStruct(ref lockTimeTemp);

                this.Version = nVersionTemp;
                this.Time    = nTimeTemp;              // POS Timestamp
                vinTemp.ForEach(i => this.Inputs.Add(i));
                voutTemp.ForEach(i => this.Outputs.Add(i));
                this.LockTime = lockTimeTemp;
            }
예제 #3
0
        private List <string> GetReceiverAddressByOutputs(TxOutList outputs)
        {
            var receivers = new List <string>();

            foreach (var output in outputs)
            {
                if (output.ScriptPubKey != null)
                {
                    var addr = output.ScriptPubKey.GetDestinationAddress(NetworkOperator.Instance.Network);
                    if (addr != null)
                    {
                        receivers.Add(addr.ToString());
                    }
                }
            }

            return(receivers.Distinct().ToList());
        }
예제 #4
0
            private void SerializeTxn(BitcoinStream stream, bool witSupported)
            {
                byte flags   = 0;
                var  version = (witSupported && (this.Inputs.Count == 0 && this.Outputs.Count > 0)) ? this.Version | NoDummyInput : this.Version;

                stream.ReadWrite(ref version);

                // POS Timestamp
                var time = this.Time;

                stream.ReadWrite(ref time);

                if (witSupported)
                {
                    // Check whether witnesses need to be serialized.
                    if (HasWitness)
                    {
                        flags |= 1;
                    }
                }
                if (flags != 0)
                {
                    // Use extended format in case witnesses are to be serialized.
                    TxInList vinDummy = new TxInList();
                    stream.ReadWrite <TxInList, TxIn>(ref vinDummy);
                    stream.ReadWrite(ref flags);
                }
                TxInList vin = this.Inputs;

                stream.ReadWrite <TxInList, TxIn>(ref vin);
                vin.Transaction = this;
                TxOutList vout = this.Outputs;

                stream.ReadWrite <TxOutList, TxOut>(ref vout);
                vout.Transaction = this;
                if ((flags & 1) != 0)
                {
                    StratisWitness wit = new StratisWitness(this.Inputs);
                    wit.ReadWrite(stream);
                }
                LockTime lockTime = this.LockTime;

                stream.ReadWriteStruct(ref lockTime);
            }
예제 #5
0
 public ElementsWitness(TxInList inputs, TxOutList outputs)
 {
     _Inputs  = inputs;
     _Outputs = outputs;
 }
예제 #6
0
            private void DeserializeTxn(BitcoinStream stream, bool witSupported)
            {
                byte flags = 0;

                UInt32 nVersionTemp = 0;

                stream.ReadWrite(ref nVersionTemp);

                // POS time stamp
                uint nTimeTemp = 0;

                stream.ReadWrite(ref nTimeTemp);

                TxInList  vinTemp  = new TxInList();
                TxOutList voutTemp = new TxOutList();

                // Try to read the vin. In case the dummy is there, this will be read as an empty vector.
                stream.ReadWrite <TxInList, TxIn>(ref vinTemp);

                var hasNoDummy = (nVersionTemp & NoDummyInput) != 0 && vinTemp.Count == 0;

                if (witSupported && hasNoDummy)
                {
                    nVersionTemp = nVersionTemp & ~NoDummyInput;
                }

                if (vinTemp.Count == 0 && witSupported && !hasNoDummy)
                {
                    // We read a dummy or an empty vin.
                    stream.ReadWrite(ref flags);
                    if (flags != 0)
                    {
                        // Assume we read a dummy and a flag.
                        stream.ReadWrite <TxInList, TxIn>(ref vinTemp);
                        vinTemp.Transaction = this;
                        stream.ReadWrite <TxOutList, TxOut>(ref voutTemp);
                        voutTemp.Transaction = this;
                    }
                    else
                    {
                        // Assume read a transaction without output.
                        voutTemp             = new TxOutList();
                        voutTemp.Transaction = this;
                    }
                }
                else
                {
                    // We read a non-empty vin. Assume a normal vout follows.
                    stream.ReadWrite <TxOutList, TxOut>(ref voutTemp);
                    voutTemp.Transaction = this;
                }
                if (((flags & 1) != 0) && witSupported)
                {
                    // The witness flag is present, and we support witnesses.
                    flags ^= 1;
                    StratisWitness wit = new StratisWitness(vinTemp);
                    wit.ReadWrite(stream);
                }
                if (flags != 0)
                {
                    // Unknown flag in the serialization
                    throw new FormatException("Unknown transaction optional data");
                }
                LockTime lockTimeTemp = LockTime.Zero;

                stream.ReadWriteStruct(ref lockTimeTemp);

                this.Version = nVersionTemp;
                this.Time    = nTimeTemp; // POS Timestamp
                vinTemp.ForEach(i => this.AddInput(i));
                voutTemp.ForEach(i => this.AddOutput(i));
                this.LockTime = lockTimeTemp;
            }
예제 #7
0
        public async Task <IEnumerable <CoinJoinDay> > GetDailyStatsAsync()
        {
            Console.WriteLine($"{coinJoinHashes.Length} coinjoins will be analyzed.");

            var days = new List <CoinJoinDay>();
            int processedCoinJoinCount = 0;
            var allInputs = new HashSet <OutPoint>();

            foreach (var batch in coinJoinHashes.Batch(8))
            {
                var txqueries = new List <Task <RawTransactionInfo> >();
                foreach (var cjHash in batch)
                {
                    txqueries.Add(Client.GetRawTransactionInfoWithCacheAsync(cjHash));
                }

                foreach (var query in txqueries)
                {
                    var txi = await query;
                    if (txi.Confirmations == 0)
                    {
                        continue;
                    }
                    if (!txi.BlockTime.HasValue)
                    {
                        continue;                          // Idk, shouldn't happen.
                    }
                    var blockTime    = txi.BlockTime.Value;
                    var blockTimeDay = new DateTimeOffset(blockTime.Year, blockTime.Month, blockTime.Day, 0, 0, 0, TimeSpan.Zero);
                    var day          = days.FirstOrDefault(x => x.BlockTimeDay == blockTimeDay);
                    if (day is null)
                    {
                        day = new CoinJoinDay(blockTimeDay);
                        days.Add(day);
                    }

                    foreach (var input in txi.Transaction.Inputs.Select(x => x.PrevOut))
                    {
                        allInputs.Add(input);
                        var inputHash = input.Hash;
                        if (IsCoinJoin(inputHash))
                        {
                            continue;
                        }

                        var inputTxi = await Client.GetRawTransactionInfoWithCacheAsync(inputHash);

                        day.AddNonMixedInputAmount(inputTxi.Transaction.Outputs[input.N].Value);
                    }

                    decimal coinJoinHashesPer100 = coinJoinHashes.Length / 100m;
                    processedCoinJoinCount++;
                    PercentageDone = processedCoinJoinCount / coinJoinHashesPer100;
                    bool displayProgress = (PercentageDone - PreviousPercentageDone) >= 1;
                    if (displayProgress)
                    {
                        Console.WriteLine($"Progress: {(int)PercentageDone}%");
                        PreviousPercentageDone = PercentageDone;
                    }
                }
            }

            foreach (var cjHash in coinJoinHashes)
            {
                // It should be always getting the tx out of memory cache, so shouldn't be a performance issue.
                var txi = await Client.GetRawTransactionInfoWithCacheAsync(cjHash);

                if (txi.Confirmations == 0)
                {
                    continue;
                }
                if (!txi.BlockTime.HasValue)
                {
                    continue;                          // Idk, shouldn't happen.
                }
                var blockTime    = txi.BlockTime.Value;
                var blockTimeDay = new DateTimeOffset(blockTime.Year, blockTime.Month, blockTime.Day, 0, 0, 0, TimeSpan.Zero);
                var day          = days.First(x => x.BlockTimeDay == blockTimeDay);

                var mixedValues = txi.Transaction.GetIndistinguishableOutputs(includeSingle: false).Select(x => x.value);
                var mixedValues2AnonTreshold  = txi.Transaction.GetIndistinguishableOutputs(includeSingle: false).Where(x => x.count > 2).Select(x => x.value);
                var mixedValues5AnonTreshold  = txi.Transaction.GetIndistinguishableOutputs(includeSingle: false).Where(x => x.count > 5).Select(x => x.value);
                var mixedValues10AnonTreshold = txi.Transaction.GetIndistinguishableOutputs(includeSingle: false).Where(x => x.count > 10).Select(x => x.value);

                TxOutList outputs = txi.Transaction.Outputs;
                for (int i = 0; i < outputs.Count; i++)
                {
                    var output = outputs[i];
                    if (mixedValues10AnonTreshold.Contains(output.Value))
                    {
                        continue;                                                   // This is mixed.
                    }
                    var outPoint = new OutPoint(cjHash, i);

                    if (allInputs.Contains(outPoint))
                    {
                        continue;
                    }

                    var txoutResponse = await Client.GetTxOutAsync(cjHash, i, includeMempool : false);

                    if (txoutResponse is { })
        public Transaction SendWallMessage(string sourceTxId, string sourcePublicAddress,
                                           string stratPrivateKey, string destinationAddress, double amountTx, double feeTx, byte[] bytesMsg)
        {
            // RPC Connection to Stratis Blockchain
            var rpc = GetRPC();

            // Can either use the raw transaction hex from a wallet's getrawtransaction CLI command, or look up the equivalent information via RPC
            Transaction tx = rpc.GetRawTransaction(uint256.Parse(sourceTxId));

            // The destination address will receive 0.0001 STRAT
            BitcoinAddress destAddress = BitcoinAddress.Create(destinationAddress, Network.StratisMain);

            // Stratis Source Address - The source address is used to store the 'change' from the transaction - THIS IS THE SIGNATURE for the attestation
            BitcoinAddress sourceAddress = BitcoinAddress.Create(sourcePublicAddress, Network.StratisMain);

            // The private key must be the key for the source address to be able to send funds from the source address (String of ~52 ASCII)
            BitcoinSecret sourcePrivateKey = new BitcoinSecret(stratPrivateKey, Network.StratisMain);

            int       outputIndex = 0;
            int       indexTx     = 0;
            TxOutList listOutTx   = tx.Outputs;

            foreach (var item in listOutTx)
            {
                string opCode = item.ScriptPubKey.ToString();
                if (opCode.StartsWith("OP_DUP OP_HASH160"))
                {
                    string sAddress = new Script(opCode).GetDestinationAddress(Network.StratisMain).ToString();
                    if (sAddress.Equals(sourcePublicAddress))
                    {
                        outputIndex = indexTx;
                    }
                }
                ++indexTx;
            }

            // For the fee to be correctly calculated, the quantity of funds in the source transaction needs to be known
            Money remainingBalance = tx.Outputs[outputIndex].Value;

            // Now that the source Transaction is obtained, the right output needs to be selected as an input for the new transaction.
            OutPoint outPoint = new OutPoint(tx, outputIndex);

            // The source transaction's output (must be unspent) is the input for the new transaction
            Transaction sendTx = new Transaction();

            sendTx.Inputs.Add(new TxIn()
            {
                PrevOut = outPoint
            });

            // Can currently only send a maximum of 40 bytes in the null data transaction (bytesMsg)
            // Also note that a nulldata transaction currently has to have a nonzero value assigned to it.
            TxOut messageTxOut = new TxOut()
            {
                Value        = new Money((decimal)0.0001, MoneyUnit.BTC),
                ScriptPubKey = TxNullDataTemplate.Instance.GenerateScriptPubKey(bytesMsg)
            };

            // For Attestation amountTx = 0.0001 STRAT is being sent to destAddress
            TxOut destTxOut = new TxOut()
            {
                Value        = new Money((decimal)amountTx, MoneyUnit.BTC),
                ScriptPubKey = destAddress.ScriptPubKey
            };
            double discBalance = feeTx + amountTx + 0.0001; // 0.0001 : nulldata transaction amount

            // This is what subsequent transactions use to prove ownership of the funds (more specifically, the private key used to create the ScriptPubKey is known)
            // Send the change back to the originating address.
            TxOut changeBackTxOut = new TxOut()
            {
                Value        = new Money(((remainingBalance.ToDecimal(MoneyUnit.BTC) - (decimal)discBalance)), MoneyUnit.BTC),
                ScriptPubKey = sourceAddress.ScriptPubKey
            };

            // changeBackTxOut = remainingBalance - 0.0001 (sent) - 0.0001 (network fee) - 0.0001 (nulldata)
            // Transactions without fees may violate consensus rules, or may not be relayed by other nodes on the network.

            // Add the outputs to the transaction being built
            sendTx.Outputs.Add(destTxOut);
            sendTx.Outputs.Add(messageTxOut);
            sendTx.Outputs.Add(changeBackTxOut);

            // Signing the transaction
            sendTx.Inputs[0].ScriptSig = sourceAddress.ScriptPubKey;

            // Sign the transaction using the specified private key
            sendTx.Sign(sourcePrivateKey, false);

            // Broadcast Transaction
            rpc.SendRawTransactionAsync(sendTx);

            return(sendTx);
        }
예제 #9
0
        private static void Main(string[] args)
        {
            // create client
            var client = new QBitNinjaClient(Network.Main);

            // parse tx id to NBitcoin.uint256 for client
            var transactionId = uint256.Parse("f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94");

            // query tx
            GetTransactionResponse transactionResponse = client.GetTransaction(transactionId).Result;

            // get NBitcoin.Transaction type
            NBitcoin.Transaction nBitcoinTransaction = transactionResponse.Transaction;

            var fromTransactionClass = nBitcoinTransaction.GetHash();

            var fromGetTransactionResponseClass = transactionResponse.TransactionId;

            Console.WriteLine(fromTransactionClass == transactionId && fromGetTransactionResponseClass == transactionId);

            List <ICoin> receivedCoins = transactionResponse.ReceivedCoins;

            // received coins
            Console.WriteLine("Begin received coins");
            foreach (var coin in receivedCoins)
            {
                Money amount = coin.Amount as Money;
                Console.WriteLine(amount?.ToDecimal(MoneyUnit.BTC));

                var paymentScript = coin.TxOut.ScriptPubKey;
                Console.WriteLine(paymentScript);

                var address = paymentScript.GetDestinationAddress(Network.Main);
                Console.WriteLine(address);
            }

            // outputs
            TxOutList outputs = nBitcoinTransaction.Outputs;

            Console.WriteLine("Begin outputs");
            foreach (var output in outputs)
            {
                Money amount = output.Value;
                Console.WriteLine(amount.ToDecimal(MoneyUnit.BTC));

                var paymentScript = output.ScriptPubKey;
                Console.WriteLine(paymentScript);

                var address = paymentScript.GetDestinationAddress(Network.Main);
                Console.WriteLine(address);
            }

            // inputs
            TxInList inputs = nBitcoinTransaction.Inputs;

            Console.WriteLine("Begin inputs");
            foreach (var input in inputs)
            {
                OutPoint previousOutPoint = input.PrevOut;
                Console.WriteLine(previousOutPoint);
                Console.WriteLine(previousOutPoint.Hash); // hash of prev tx
                Console.WriteLine(previousOutPoint.N);    // index of out from prev tx, that has been spent in current tx
            }

            // The terms TxOut, Output and out are synonymous.

            // create a txout with 21 bitcoin from the first ScriptPubKey in our current transaction:
            Console.WriteLine("Begin txout");
            Money twentyBtc    = new Money(21, MoneyUnit.BTC);
            var   scriptPubKey = nBitcoinTransaction.Outputs.FirstOrDefault()?.ScriptPubKey;
            TxOut txOut        = new TxOut(twentyBtc, scriptPubKey);

            Console.WriteLine(txOut.Value.ToDecimal(MoneyUnit.BTC));
            Console.WriteLine(txOut.ScriptPubKey);

            // every TxOut is uniq addressed by at the blockchain level by the id of the tx, including the index
            // e.g., OutPoint of TxOut is

            Console.WriteLine("Begin outpoint");
            OutPoint firstOutPoint = receivedCoins.FirstOrDefault()?.Outpoint;

            Console.WriteLine(firstOutPoint?.Hash);
            Console.WriteLine(firstOutPoint?.N);

            Console.WriteLine("Begin txin");
            // TxIn is composed of the Outpoint of the TxOut being spent and of the ScriptSig (we can see the ScriptSig as the “Proof of Ownership”).
            // with the previous transaction ID, we can review the info associated with that tx
            OutPoint firstPreviousOutPoint = nBitcoinTransaction.Inputs.FirstOrDefault()?.PrevOut;

            if (firstPreviousOutPoint != null)
            {
                var firstPreviousTransaction = client.GetTransaction(firstPreviousOutPoint.Hash).Result.Transaction;
                Console.WriteLine(firstPreviousTransaction.IsCoinBase);
            }

            Console.WriteLine("begin coin base hunt");
            //TraceCoinBase(nBitcoinTransaction, client); just done as an exercise, do not use


            Console.WriteLine("begin total output value count");
            var spentCoins = transactionResponse.SpentCoins;

            var spentAmount = spentCoins.Aggregate(Money.Zero,
                                                   (money, next) =>
                                                   (Money)next.Amount.Add(money)).ToDecimal(MoneyUnit.BTC);

            Console.WriteLine(spentAmount);

            var receivedAmount = receivedCoins.Aggregate(Money.Zero,
                                                         (money, next) =>
                                                         (Money)next.Amount.Add(money)).ToDecimal(MoneyUnit.BTC);

            Console.WriteLine(receivedAmount);

            Console.WriteLine(spentAmount - receivedAmount); // fee

            var fee = nBitcoinTransaction.GetFee(spentCoins.ToArray()).ToDecimal(MoneyUnit.BTC);

            Console.WriteLine(fee);

            // note: there are no fee in a coinbase transaction

            Console.ReadLine();
        }