Beispiel #1
0
 void Start()
 {
     log  = GetComponent <LogScript>();
     _out = GetComponent <OutputScript>();
     log.AddEvent("====================== Progress Log =======================");
     _out.AddEvent("======================= Output Log ========================");
 }
Beispiel #2
0
                public UncontrolledOutput(Amount amount, byte[] pkScript) : base(amount)
                {
                    if (pkScript == null)
                    {
                        throw new ArgumentNullException(nameof(pkScript));
                    }

                    PkScript = OutputScript.ParseScript(pkScript);
                }
Beispiel #3
0
        public static UnspentOutput MarshalUnspentOutput(FundTransactionResponse.Types.PreviousOutput o)
        {
            var txHash         = new Sha256Hash(o.TransactionHash.ToByteArray());
            var outputIndex    = o.OutputIndex;
            var amount         = (Amount)o.Amount;
            var pkScript       = OutputScript.ParseScript(o.PkScript.ToByteArray());
            var seenTime       = DateTimeOffsetExtras.FromUnixTimeSeconds(o.ReceiveTime);
            var isFromCoinbase = o.FromCoinbase;

            return(new UnspentOutput(txHash, outputIndex, amount, pkScript, seenTime, isFromCoinbase));
        }
Beispiel #4
0
        /// <summary>
        /// Extracts the public key hash from a raw p2pkh script
        /// </summary>
        /// <param name="rawPkScript"></param>
        /// <returns></returns>
        /// <exception cref="SigningException"></exception>
        private static byte[] GetPublicKeyHash(byte[] rawPkScript)
        {
            // Only support Secp256k1 signatures
            var outScript = OutputScript.ParseScript(rawPkScript);

            if (!(outScript is OutputScript.Secp256k1PubKeyHash parsedScript))
            {
                throw new SigningException("Unsupported signature script type");
            }

            return(parsedScript.Hash160);
        }
        public UnspentOutput(Blake256Hash txHash, uint outputIndex, Amount amount, OutputScript pkScript, DateTimeOffset seenTime, bool isFromCoinbase)
        {
            if (txHash == null)
            {
                throw new ArgumentNullException(nameof(txHash));
            }
            if (pkScript == null)
            {
                throw new ArgumentNullException(nameof(pkScript));
            }

            TransactionHash = txHash;
            OutputIndex     = outputIndex;
            Amount          = amount;
            PkScript        = pkScript;
            SeenTime        = seenTime;
            IsFromCoinbase  = IsFromCoinbase;
        }
Beispiel #6
0
        public static bool TryFromOutputScript(OutputScript pkScript, BlockChainIdentity intendedBlockChain, out Address address)
        {
            var payToPubKeyHashScript = pkScript as OutputScript.PubKeyHash;

            if (payToPubKeyHashScript != null)
            {
                address = new PayToPubKeyHash(intendedBlockChain, payToPubKeyHashScript.Hash160);
                return(true);
            }

            var payToScriptHashScript = pkScript as OutputScript.ScriptHash;

            if (payToScriptHashScript != null)
            {
                address = new PayToScriptHash(intendedBlockChain, payToScriptHashScript.Hash160);
                return(true);
            }

            address = null;
            return(false);
        }
        /// <summary>
        /// Potentially adds a change output to a transaction to set an appropiate fee.
        /// </summary>
        public static Transaction AddChange(Transaction tx, Amount totalInput, OutputScript changeScript, Amount feePerKb)
        {
            if (tx == null)
            {
                throw new ArgumentNullException(nameof(tx));
            }
            if (totalInput < 0)
            {
                throw Errors.RequireNonNegative(nameof(totalInput));
            }
            if (changeScript == null)
            {
                throw new ArgumentNullException(nameof(changeScript));
            }
            if (feePerKb < 0)
            {
                throw Errors.RequireNonNegative(nameof(feePerKb));
            }

            var txSerializeSizeEstimate = Transaction.EstimateSerializeSize(tx.Inputs.Length, tx.Outputs, true);
            var feeEstimate             = FeeForSerializeSize(feePerKb, txSerializeSizeEstimate);

            var totalNonChangeOutput = tx.Outputs.Sum(o => o.Amount);
            var changeAmount         = totalInput - totalNonChangeOutput - feeEstimate;
            var changeOutput         = new Transaction.Output(changeAmount, Transaction.SupportedVersion, changeScript.Script);

            // Change should not be created if the change output itself would be considered dust.
            if (TransactionRules.IsDust(changeOutput, feePerKb))
            {
                return(tx);
            }

            var outputList = tx.Outputs.ToList();

            outputList.Add(changeOutput); // TODO: Randomize change output position.
            var outputs = outputList.ToArray();

            return(new Transaction(tx.Version, tx.Inputs, outputs, tx.LockTime, tx.Expiry));
        }
Beispiel #8
0
        public async Task <Tuple <List <UnspentOutput>, Amount, OutputScript> > FundTransactionAsync(
            Account account, Amount targetAmount, int requiredConfirmations)
        {
            var client  = WalletService.NewClient(_channel);
            var request = new FundTransactionRequest
            {
                Account                  = account.AccountNumber,
                TargetAmount             = targetAmount,
                RequiredConfirmations    = requiredConfirmations,
                IncludeImmatureCoinbases = false,
                IncludeChangeScript      = true,
            };
            var response = await client.FundTransactionAsync(request, cancellationToken : _tokenSource.Token);

            var outputs      = response.SelectedOutputs.Select(MarshalUnspentOutput).ToList();
            var total        = (Amount)response.TotalAmount;
            var changeScript = (OutputScript)null;

            if (response.ChangePkScript?.Length != 0)
            {
                changeScript = OutputScript.ParseScript(response.ChangePkScript.ToByteArray());
            }
            return(Tuple.Create(outputs, total, changeScript));
        }
Beispiel #9
0
 void Start()
 {
     log  = GetComponent <LogScript>();
     _out = GetComponent <OutputScript>();
 }
Beispiel #10
0
        /// <summary>
        /// Constructs an unsigned transaction by referencing previous unspent outputs.
        /// A change output is added when necessary to return extra value back to the wallet.
        /// </summary>
        /// <param name="outputs">Transaction output array without change.</param>
        /// <param name="changeScript">Output script to pay change to.</param>
        /// <param name="fetchInputsAsync">Input selection source.</param>
        /// <returns>Unsigned transaction and total input amount.</returns>
        /// <exception cref="InsufficientFundsException">Input source was unable to provide enough input value.</exception>
        public static async Task <Tuple <Transaction, Amount> > BuildUnsignedTransaction(Transaction.Output[] outputs,
                                                                                         OutputScript changeScript,
                                                                                         Amount feePerKb,
                                                                                         InputSource fetchInputsAsync)
        {
            if (outputs == null)
            {
                throw new ArgumentNullException(nameof(outputs));
            }
            if (changeScript == null)
            {
                throw new ArgumentNullException(nameof(changeScript));
            }
            if (fetchInputsAsync == null)
            {
                throw new ArgumentNullException(nameof(fetchInputsAsync));
            }

            var targetAmount  = outputs.Sum(o => o.Amount);
            var estimatedSize = Transaction.EstimateSerializeSize(1, outputs, true);
            var targetFee     = TransactionFees.FeeForSerializeSize(feePerKb, estimatedSize);

            while (true)
            {
                var funding = await fetchInputsAsync(targetAmount + targetFee);

                var inputAmount = funding.Item1;
                var inputs      = funding.Item2;
                if (inputAmount < targetAmount + targetFee)
                {
                    throw new InsufficientFundsException();
                }

                var unsignedTransaction = new Transaction(Transaction.SupportedVersion, inputs, outputs, 0, 0);
                if (inputAmount > targetAmount + targetFee)
                {
                    unsignedTransaction = TransactionFees.AddChange(unsignedTransaction, inputAmount,
                                                                    changeScript, feePerKb);
                }

                if (TransactionFees.EstimatedFeePerKb(unsignedTransaction, inputAmount) < feePerKb)
                {
                    estimatedSize = Transaction.EstimateSerializeSize(inputs.Length, outputs, true);
                    targetFee     = TransactionFees.FeeForSerializeSize(feePerKb, estimatedSize);
                }
                else
                {
                    return(Tuple.Create(unsignedTransaction, inputAmount));
                }
            }
        }
Beispiel #11
0
        private void Peer_NewMessage(object sender, Message message)
        {
            if (ProcessedMessages.Contains(message))
            {
                return;
            }
            ProcessedMessages.Add(message);
            Console.Write($"{Name} received message: ");
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(message);
            Console.ResetColor();

            NewMessage?.Invoke(this, message);

            if (message.Type == MessageType.PublicKey)
            {
                var pubKey = new PubKey(message.GetDataString());
                AllPubKeys.Add(pubKey);

                if (AllPubKeys.Count == RequiredPeerCount)
                {
                    // every participant (say participant i in a predefined shuffling
                    // order) uses the encryption keys of every participant j > i to create a layered
                    // encryption of her output address.
                    string onion = OnionEncrypt(AllPubKeys, OutputScript.ToString());
                    Broadcast(new Message(MessageType.Onions, onion));
                }
            }
            else if (message.Type == MessageType.Onions)
            {
                var onions = message.GetDataCollection();
                if (onions.Count() == 1)
                {
                    Onions.Add(onions.Single());

                    if (Onions.Count == RequiredPeerCount)
                    {
                        if (SecretKey.CanDecrypt(Onions.First()))
                        {
                            var stripped = Decrypt(SecretKey, Onions).ToList();
                            stripped.Shuffle();
                            Broadcast(new Message(MessageType.Onions, stripped));
                        }
                    }
                }
                else if (SecretKey.CanDecrypt(onions.First()))
                {
                    var stripped = Decrypt(SecretKey, onions).ToList();
                    stripped.Shuffle();

                    if (NBitcoinHelpers.IsScript(stripped.First()))
                    {
                        Broadcast(new Message(MessageType.ShuffledScripts, stripped));
                    }
                    else
                    {
                        Broadcast(new Message(MessageType.Onions, stripped));
                    }
                }
            }
        }