void Start() { log = GetComponent <LogScript>(); _out = GetComponent <OutputScript>(); log.AddEvent("====================== Progress Log ======================="); _out.AddEvent("======================= Output Log ========================"); }
public UncontrolledOutput(Amount amount, byte[] pkScript) : base(amount) { if (pkScript == null) { throw new ArgumentNullException(nameof(pkScript)); } PkScript = OutputScript.ParseScript(pkScript); }
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)); }
/// <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; }
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)); }
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)); }
void Start() { log = GetComponent <LogScript>(); _out = GetComponent <OutputScript>(); }
/// <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)); } } }
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)); } } } }