Пример #1
0
        public int EstimateSize(Transaction tx)
        {
            var clone = tx.Clone();

            clone.Inputs.Clear();
            var baseSize = clone.ToBytes().Length;

            int inputSize = 0;

            for (int i = 0; i < tx.Inputs.Count; i++)
            {
                var txin = tx.Inputs[i];
                var coin = FindCoin(txin.PrevOut);
                if (coin == null)
                {
                    throw CoinNotFound(txin);
                }
                inputSize += EstimateScriptSigSize(coin) + 41;
            }

            return(baseSize + inputSize);
        }
Пример #2
0
 private PSBT(Transaction transaction)
 {
     if (transaction == null)
     {
         throw new ArgumentNullException(nameof(transaction));
     }
     tx      = transaction.Clone();
     Inputs  = new PSBTInputList();
     Outputs = new PSBTOutputList();
     for (var i = 0; i < tx.Inputs.Count; i++)
     {
         this.Inputs.Add(new PSBTInput(this, (uint)i, tx.Inputs[i]));
     }
     for (var i = 0; i < tx.Outputs.Count; i++)
     {
         this.Outputs.Add(new PSBTOutput(this, (uint)i, tx.Outputs[i]));
     }
     foreach (var input in tx.Inputs)
     {
         input.ScriptSig = Script.Empty;
         input.WitScript = WitScript.Empty;
     }
 }
Пример #3
0
        public bool TryFinalizeInput(out IList <PSBTError> errors)
        {
            errors = null;
            if (IsFinalized())
            {
                return(true);
            }
            var isSane = this.CheckSanity();

            if (isSane.Count != 0)
            {
                errors = isSane;
                return(false);
            }
            if (witness_utxo == null && non_witness_utxo == null)
            {
                errors = new List <PSBTError>()
                {
                    new PSBTError(Index, "Neither witness_utxo nor non_witness_output is set")
                };
                return(false);
            }
            var coin = this.GetSignableCoin(out var getSignableCoinError) ?? this.GetCoin();             // GetCoin can't be null at this stage.
            TransactionBuilder transactionBuilder = Parent.CreateTransactionBuilder();

            transactionBuilder.AddCoins(coin);
            foreach (var sig in PartialSigs)
            {
                transactionBuilder.AddKnownSignature(sig.Key, sig.Value, coin.Outpoint);
            }
            Transaction signed = null;

            try
            {
                var signedTx = Parent.Settings.IsSmart ? Parent.GetOriginalTransaction() : Transaction.Clone();
                signed = transactionBuilder.SignTransaction(signedTx, SigHash.All);
            }
            catch (Exception ex)
            {
                errors = new List <PSBTError>()
                {
                    new PSBTError(Index, $"Error while finalizing the input \"{getSignableCoinError ?? ex.Message}\"")
                };
                return(false);
            }
            var indexedInput = signed.Inputs.FindIndexedInput(coin.Outpoint);

            if (!indexedInput.VerifyScript(coin, out var error))
            {
                errors = new List <PSBTError>()
                {
                    new PSBTError(Index, $"The finalized input script does not properly validate \"{error}\"")
                };
                return(false);
            }

            FinalScriptSig     = indexedInput.ScriptSig is Script oo && oo != Script.Empty ? oo : null;
            FinalScriptWitness = indexedInput.WitScript is WitScript o && o != WitScript.Empty ? o : null;
            if (transactionBuilder.FindSignableCoin(indexedInput) is ScriptCoin scriptCoin)
            {
                if (scriptCoin.IsP2SH)
                {
                    RedeemScript = scriptCoin.GetP2SHRedeem();
                }
                if (scriptCoin.RedeemType == RedeemType.WitnessV0)
                {
                    WitnessScript = scriptCoin.Redeem;
                }
            }
            ClearForFinalize();
            errors = null;
            return(true);
        }
Пример #4
0
        public Transaction SignTransaction(KeyPath keyPath, ICoin[] signedCoins, Transaction[] parents, Transaction transaction)
        {
            using(Transport.Lock())
            {
                var pubkey = GetWalletPubKey(keyPath).UncompressedPublicKey.Compress();
                var parentsById = parents.ToDictionary(p => p.GetHash());
                var coinsByPrevout = signedCoins.ToDictionary(c => c.Outpoint);

                List<TrustedInput> trustedInputs = new List<TrustedInput>();
                foreach(var input in transaction.Inputs)
                {
                    Transaction parent;
                    parentsById.TryGetValue(input.PrevOut.Hash, out parent);
                    if(parent == null)
                        throw new KeyNotFoundException("Parent transaction " + input.PrevOut.Hash + " not found");
                    trustedInputs.Add(GetTrustedInput(parent, (int)input.PrevOut.N));
                }

                var inputs = trustedInputs.ToArray();

                transaction = transaction.Clone();

                foreach(var input in transaction.Inputs)
                {
                    ICoin previousCoin = null;
                    coinsByPrevout.TryGetValue(input.PrevOut, out previousCoin);

                    if(previousCoin != null)
                        input.ScriptSig = previousCoin.GetScriptCode();
                }

                bool newTransaction = true;
                foreach(var input in transaction.Inputs.AsIndexedInputs())
                {
                    ICoin coin = null;
                    if(!coinsByPrevout.TryGetValue(input.PrevOut, out coin))
                        continue;

                    UntrustedHashTransactionInputStart(newTransaction, input, inputs);
                    newTransaction = false;

                    UntrustedHashTransactionInputFinalizeFull(transaction.Outputs);

                    var sig = UntrustedHashSign(keyPath, null, transaction.LockTime, SigHash.All);
                    input.ScriptSig = PayToPubkeyHashTemplate.Instance.GenerateScriptSig(sig, pubkey);
                    ScriptError error;
                    if(!Script.VerifyScript(coin.TxOut.ScriptPubKey, transaction, (int)input.Index, Money.Zero, out error))
                        return null;
                }

                return transaction;
            }
        }
Пример #5
0
		private Transaction CombineSignaturesCore(Transaction signed1, Transaction signed2)
		{
			if(signed1 == null)
				return signed2;
			if(signed2 == null)
				return signed1;
			var tx = signed1.Clone();
			for(int i = 0; i < tx.Inputs.Count; i++)
			{
				if(i >= signed2.Inputs.Count)
					break;

				var txIn = tx.Inputs[i];

				var coin = FindCoin(txIn.PrevOut);
				var scriptPubKey = coin == null
					? (DeduceScriptPubKey(txIn.ScriptSig) ?? DeduceScriptPubKey(signed2.Inputs[i].ScriptSig))
					: coin.TxOut.ScriptPubKey;

				Money amount = null;
				if(coin != null)
					amount = coin is IColoredCoin ? ((IColoredCoin)coin).Bearer.Amount : ((Coin)coin).Amount;
				var result = Script.CombineSignatures(
									scriptPubKey,
									new TransactionChecker(tx, i, amount),
									 GetScriptSigs(signed1.Inputs.AsIndexedInputs().Skip(i).First()),
									 GetScriptSigs(signed2.Inputs.AsIndexedInputs().Skip(i).First()));
				var input = tx.Inputs.AsIndexedInputs().Skip(i).First();
				input.WitScript = result.WitSig;
				input.ScriptSig = result.ScriptSig;
			}
			return tx;
		}
Пример #6
0
		/// <summary>
		/// Allows to keep building on the top of a partially built transaction
		/// </summary>
		/// <param name="transaction">Transaction to complete</param>
		/// <returns></returns>
		public TransactionBuilder ContinueToBuild(Transaction transaction)
		{
			if(_CompletedTransaction != null)
				throw new InvalidOperationException("Transaction to complete already set");
			_CompletedTransaction = transaction.Clone();
			return this;
		}
Пример #7
0
		public int EstimateSize(Transaction tx)
		{
			if(tx == null)
				throw new ArgumentNullException("tx");
			var clone = tx.Clone();
			clone.Inputs.Clear();
			var baseSize = clone.ToBytes().Length;

			int inputSize = 0;
			foreach(var txin in tx.Inputs.AsIndexedInputs())
			{
				var coin = FindSignableCoin(txin) ?? FindCoin(txin.PrevOut);
				if(coin == null)
					throw CoinNotFound(txin);
				inputSize += EstimateScriptSigSize(coin) + 41;
			}

			return baseSize + inputSize;
		}
Пример #8
0
		public Transaction SignTransaction(Transaction transaction, SigHash sigHash)
		{
			var tx = transaction.Clone();
			SignTransactionInPlace(tx, sigHash);
			return tx;
		}