Exemplo n.º 1
0
        private long CountWitnessSigOps(Script scriptSig, Script scriptPubKey, WitScript witness, DeploymentFlags flags)
        {
            witness = witness ?? WitScript.Empty;
            if (!flags.ScriptFlags.HasFlag(ScriptVerify.Witness))
            {
                return(0);
            }

            WitProgramParameters witParams = PayToWitTemplate.Instance.ExtractScriptPubKeyParameters2(scriptPubKey);

            if (witParams != null)
            {
                return(this.WitnessSigOps(witParams, witness, flags));
            }

            if (scriptPubKey.IsPayToScriptHash && scriptSig.IsPushOnly)
            {
                byte[] data      = scriptSig.ToOps().Select(o => o.PushData).LastOrDefault() ?? new byte[0];
                Script subScript = Script.FromBytesUnsafe(data);

                witParams = PayToWitTemplate.Instance.ExtractScriptPubKeyParameters2(scriptPubKey);
                if (witParams != null)
                {
                    return(this.WitnessSigOps(witParams, witness, flags));
                }
            }

            return(0);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Calculates signature operation cost for single transaction input.
        /// </summary>
        /// <param name="scriptPubKey">Script public key.</param>
        /// <param name="witness">Witness script.</param>
        /// <param name="flags">Script verification flags.</param>
        /// <returns>Signature operation cost for single transaction input.</returns>
        private long CountWitnessSignatureOperation(Script scriptPubKey, WitScript witness, DeploymentFlags flags)
        {
            witness = witness ?? WitScript.Empty;
            if (!flags.ScriptFlags.HasFlag(ScriptVerify.Witness))
            {
                return(0);
            }

            WitProgramParameters witParams = PayToWitTemplate.Instance.ExtractScriptPubKeyParameters2(this.Parent.Network, scriptPubKey);

            if (witParams?.Version == 0)
            {
                if (witParams.Program.Length == 20)
                {
                    return(1);
                }

                if (witParams.Program.Length == 32 && witness.PushCount > 0)
                {
                    Script subscript = Script.FromBytesUnsafe(witness.GetUnsafePush(witness.PushCount - 1));
                    return(subscript.GetSigOpCount(true, this.Parent.Network));
                }
            }

            return(0);
        }
Exemplo n.º 3
0
        internal TxOut orphanTxOut           = null; // When this input is not segwit, but we don't have the previous tx
        //

        internal PSBTInput(PSBT parent, uint index, TxIn input) : base(parent)
        {
            TxIn              = input;
            Index             = index;
            originalScriptSig = TxIn.ScriptSig ?? Script.Empty;
            originalWitScript = TxIn.WitScript ?? WitScript.Empty;
        }
        /// <summary>
        /// Adds a witness stack to the list of elements that will be used for building the filter.
        /// </summary>
        /// <param name="witScript">The witScript.</param>
        /// <returns>The updated filter builder instance.</returns>
        public void AddWitness(WitScript witScript)
        {
            if (witScript == null)
            {
                throw new ArgumentNullException(nameof(witScript));
            }

            AddEntries(witScript.Pushes);
        }
Exemplo n.º 5
0
 public void ReadWrite(BitcoinStream bitcoinStream)
 {
     bitcoinStream.ReadWrite(ref _scriptSig);
     if (bitcoinStream.Serializing)
     {
         Witness.WriteToStream(bitcoinStream);
     }
     else
     {
         Witness = WitScript.Load(bitcoinStream);
     }
 }
Exemplo n.º 6
0
        public static TxDestination GetSigner(WitScript witScript)
        {
            if (witScript == WitScript.Empty)
            {
                return(null);
            }
            var parameters = PayToWitPubKeyHashTemplate.Instance.ExtractWitScriptParameters(witScript);

            if (parameters != null)
            {
                return(parameters.PublicKey.WitHash);
            }
            return(Script.FromBytesUnsafe(witScript.GetUnsafePush(witScript.PushCount - 1)).WitHash);
        }
Exemplo n.º 7
0
        private void UnSerialize(BitcoinStream stream)
        {
            var fAllowWitness = stream.TransactionOptions.HasFlag(TransactionOptions.Witness) && stream.ProtocolCapabilities.SupportWitness;

            // Detect dynamic federation block serialization using "HF bit",
            // or the signed bit which is invalid in Bitcoin
            var isDynamic = false;
            int version   = 0;

            stream.ReadWrite(ref version);
            isDynamic     = version < 0;
            this.nVersion = ~DYNAFED_HF_MASK & version;

            if (isDynamic)
            {
                stream.ReadWrite(ref hashPrevBlock);
                stream.ReadWrite(ref hashMerkleRoot);
                stream.ReadWrite(ref nTime);
                stream.ReadWrite(ref _nHeight);
                stream.ReadWrite(ref DynaFedParams);
                // We do not serialize witness for hashes, or weight calculation
                if (stream.Type != SerializationType.Hash && fAllowWitness)
                {
                    SignBlockWitness = WitScript.Load(stream);
                }
            }
            else
            {
                stream.ReadWrite(ref hashPrevBlock);
                stream.ReadWrite(ref hashMerkleRoot);
                stream.ReadWrite(ref nTime);
                if (ElementsParams <TNetwork> .BlockHeightInHeader)
                {
                    stream.ReadWrite(ref _nHeight);
                }

                if (ElementsParams <TNetwork> .SignedBlocks)
                {
                    stream.ReadWrite(ref _Proof);
                }
                else
                {
                    stream.ReadWrite(ref nBits);
                    stream.ReadWrite(ref nNonce);
                }
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Extract witness redeem from WitScript
        /// </summary>
        /// <param name="witScript">Witscript to extract information from</param>
        /// <param name="expectedScriptId">Expected redeem hash</param>
        /// <returns>The witness redeem</returns>
        public Script ExtractWitScriptParameters(WitScript witScript, WitScriptId expectedScriptId = null)
        {
            if (witScript.PushCount == 0)
            {
                return(null);
            }
            var    last   = witScript.GetUnsafePush(witScript.PushCount - 1);
            Script redeem = new Script(last);

            if (expectedScriptId != null)
            {
                if (expectedScriptId != redeem.WitHash)
                {
                    return(null);
                }
            }
            return(redeem);
        }
Exemplo n.º 9
0
        private long WitnessSigOps(WitProgramParameters witParams, WitScript witScript, ConsensusFlags flags)
        {
            if (witParams.Version == 0)
            {
                if (witParams.Program.Length == 20)
                {
                    return(1);
                }

                if (witParams.Program.Length == 32 && witScript.PushCount > 0)
                {
                    Script subscript = Script.FromBytesUnsafe(witScript.GetUnsafePush(witScript.PushCount - 1));
                    return(subscript.GetSigOpCount(true));
                }
            }

            // Future flags may be implemented here.
            return(0);
        }
Exemplo n.º 10
0
 public PayToWitPubkeyHashScriptSigParameters ExtractWitScriptParameters(WitScript witScript)
 {
     if (!CheckWitScriptCore(witScript))
     {
         return(null);
     }
     try
     {
         return(new PayToWitPubkeyHashScriptSigParameters()
         {
             TransactionSignature = (witScript[0].Length == 1 && witScript[0][0] == 0) ? null : new TransactionSignature(witScript[0]),
             PublicKey = new PubKey(witScript[1], true),
         });
     }
     catch (FormatException)
     {
         return(null);
     }
 }
Exemplo n.º 11
0
            internal void ReadWrite(BitcoinStream stream)
            {
                for (int i = 0; i < _Inputs.Count; i++)
                {
                    if (stream.Serializing)
                    {
                        var bytes = (_Inputs[i].WitScript ?? WitScript.Empty).ToBytes();
                        stream.ReadWrite(ref bytes);
                    }
                    else
                    {
                        _Inputs[i].WitScript = WitScript.Load(stream);
                    }
                }

                if (IsNull())
                {
                    throw new FormatException("Superfluous witness record");
                }
            }
Exemplo n.º 12
0
        protected virtual byte[] SerializeOutputTransaction(Transaction tx)
        {
            using (var stream = new MemoryStream())
            {
                var bs = new BitcoinStream(stream, true);

                // serialize outputs
                var vout = tx.Outputs;
                bs.ReadWrite <TxOutList, TxOut>(ref vout);

                // serialize witness (segwit)
                if (!string.IsNullOrEmpty(BlockTemplate.DefaultWitnessCommitment))
                {
                    var witScript = new WitScript(BlockTemplate.DefaultWitnessCommitment);
                    var raw       = witScript.ToBytes();
                    bs.ReadWrite(ref raw);
                }

                return(stream.ToArray());
            }
        }
        public Transaction ReSign(Coin coin, out bool cached)
        {
            var transaction = Transaction.Clone();

            if (coin.Outpoint == SignedOutpoint)
            {
                transaction.Inputs[0].WitScript = Signature;
                transaction.Inputs[0].PrevOut   = SignedOutpoint;
                cached = true;
                return(transaction);
            }
            transaction.Inputs[0].PrevOut = coin.Outpoint;

            //TODO: REMOVE THIS LATER hack so old tx do not crash client
            if (transaction.Inputs[0].WitScript.PushCount == 0)
            {
                transaction.Inputs[0].WitScript = Signature;
                transaction.Inputs[0].PrevOut   = SignedOutpoint;
                cached = true;
                return(transaction);
            }

            var redeem     = new Script(transaction.Inputs[0].WitScript.Pushes.Last());
            var scriptCoin = coin.ToScriptCoin(redeem);

            byte[]        signature         = transaction.SignInput(Key, scriptCoin).ToBytes();
            List <byte[]> resignedScriptSig = new List <byte[]>();

            foreach (var op in transaction.Inputs[0].WitScript.Pushes)
            {
                resignedScriptSig.Add(IsPlaceholder(op) ? signature : op);
            }
            Signature      = new WitScript(resignedScriptSig.ToArray());
            SignedOutpoint = coin.Outpoint;
            transaction.Inputs[0].WitScript = Signature;
            cached = false;
            return(transaction);
        }
Exemplo n.º 14
0
		private bool CheckWitScriptCore(WitScript witScript)
		{
			return witScript.PushCount == 2 &&
				   ((witScript[0].Length == 1 && witScript[0][0] == 0) || (TransactionSignature.IsValid(witScript[0], ScriptVerify.None))) &&
				   PubKey.Check(witScript[1], false);
		}
        public async Task <IActionResult> PostSignaturesAsync([FromQuery, Required] string uniqueId, [FromQuery, Required] long roundId, [FromBody, Required] IDictionary <int, string> signatures)
        {
            if (roundId < 0 ||
                !signatures.Any() ||
                signatures.Any(x => x.Key < 0 || string.IsNullOrWhiteSpace(x.Value)) ||
                !ModelState.IsValid)
            {
                return(BadRequest());
            }

            (CoordinatorRound round, Alice alice) = GetRunningRoundAndAliceOrFailureResponse(roundId, uniqueId, RoundPhase.Signing, out IActionResult returnFailureResponse);
            if (returnFailureResponse != null)
            {
                return(returnFailureResponse);
            }

            // Check if Alice provided signature to all her inputs.
            if (signatures.Count != alice.Inputs.Count())
            {
                return(BadRequest("Alice did not provide enough witnesses."));
            }

            RoundPhase phase = round.Phase;

            switch (phase)
            {
            case RoundPhase.Signing:
            {
                using (await SigningLock.LockAsync())
                {
                    foreach (var signaturePair in signatures)
                    {
                        int       index   = signaturePair.Key;
                        WitScript witness = null;
                        try
                        {
                            witness = new WitScript(signaturePair.Value);
                        }
                        catch (Exception ex)
                        {
                            return(BadRequest($"Malformed witness is provided. Details: {ex.Message}"));
                        }
                        int maxIndex = round.UnsignedCoinJoin.Inputs.Count - 1;
                        if (maxIndex < index)
                        {
                            return(BadRequest($"Index out of range. Maximum value: {maxIndex}. Provided value: {index}"));
                        }

                        // Check duplicates.
                        if (round.SignedCoinJoin.Inputs[index].HasWitScript())
                        {
                            return(BadRequest("Input is already signed."));
                        }

                        // Verify witness.
                        // 1. Copy UnsignedCoinJoin.
                        Transaction cjCopy = Transaction.Parse(round.UnsignedCoinJoin.ToHex(), Network);
                        // 2. Sign the copy.
                        cjCopy.Inputs[index].WitScript = witness;
                        // 3. Convert the current input to IndexedTxIn.
                        IndexedTxIn currentIndexedInput = cjCopy.Inputs.AsIndexedInputs().Skip(index).First();
                        // 4. Find the corresponding registered input.
                        Coin registeredCoin = alice.Inputs.Single(x => x.Outpoint == cjCopy.Inputs[index].PrevOut);
                        // 5. Verify if currentIndexedInput is correctly signed, if not, return the specific error.
                        if (!currentIndexedInput.VerifyScript(registeredCoin, out ScriptError error))
                        {
                            return(BadRequest($"Invalid witness is provided. {nameof(ScriptError)}: {error}."));
                        }

                        // Finally add it to our CJ.
                        round.SignedCoinJoin.Inputs[index].WitScript = witness;
                    }

                    alice.State = AliceState.SignedCoinJoin;

                    await round.BroadcastCoinJoinIfFullySignedAsync();
                }

                return(NoContent());
            }

            default:
            {
                TryLogLateRequest(roundId, RoundPhase.Signing);
                return(Conflict($"CoinJoin can only be requested from Signing phase. Current phase: {phase}."));
            }
            }
        }
        /// <inheritdoc />
        public virtual void ContextualCheckBlock(RuleContext context)
        {
            this.logger.LogTrace("()");

            Block           block           = context.BlockValidationContext.Block;
            DeploymentFlags deploymentFlags = context.Flags;

            int height = context.BestBlock == null ? 0 : context.BestBlock.Height + 1;

            // Start enforcing BIP113 (Median Time Past) using versionbits logic.
            DateTimeOffset lockTimeCutoff = deploymentFlags.LockTimeFlags.HasFlag(Transaction.LockTimeFlags.MedianTimePast) ?
                                            context.BestBlock.MedianTimePast :
                                            block.Header.BlockTime;

            // Check that all transactions are finalized.
            foreach (Transaction transaction in block.Transactions)
            {
                if (!transaction.IsFinal(lockTimeCutoff, height))
                {
                    this.logger.LogTrace("(-)[TX_NON_FINAL]");
                    ConsensusErrors.BadTransactionNonFinal.Throw();
                }
            }

            // Enforce rule that the coinbase starts with serialized block height.
            if (deploymentFlags.EnforceBIP34)
            {
                var    expect = new Script(Op.GetPushOp(height));
                Script actual = block.Transactions[0].Inputs[0].ScriptSig;
                if (!this.StartWith(actual.ToBytes(true), expect.ToBytes(true)))
                {
                    this.logger.LogTrace("(-)[BAD_COINBASE_HEIGHT]");
                    ConsensusErrors.BadCoinbaseHeight.Throw();
                }
            }

            // Validation for witness commitments.
            // * We compute the witness hash (which is the hash including witnesses) of all the block's transactions, except the
            //   coinbase (where 0x0000....0000 is used instead).
            // * The coinbase scriptWitness is a stack of a single 32-byte vector, containing a witness nonce (unconstrained).
            // * We build a merkle tree with all those witness hashes as leaves (similar to the hashMerkleRoot in the block header).
            // * There must be at least one output whose scriptPubKey is a single 36-byte push, the first 4 bytes of which are
            //   {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness nonce). In case there are
            //   multiple, the last one is used.
            bool haveWitness = false;

            if (deploymentFlags.ScriptFlags.HasFlag(ScriptVerify.Witness))
            {
                int commitpos = this.GetWitnessCommitmentIndex(block);
                if (commitpos != -1)
                {
                    uint256 hashWitness = this.BlockWitnessMerkleRoot(block, out bool unused);

                    // The malleation check is ignored; as the transaction tree itself
                    // already does not permit it, it is impossible to trigger in the
                    // witness tree.
                    WitScript witness = block.Transactions[0].Inputs[0].WitScript;
                    if ((witness.PushCount != 1) || (witness.Pushes.First().Length != 32))
                    {
                        this.logger.LogTrace("(-)[BAD_WITNESS_NONCE_SIZE]");
                        ConsensusErrors.BadWitnessNonceSize.Throw();
                    }

                    var hashed = new byte[64];
                    Buffer.BlockCopy(hashWitness.ToBytes(), 0, hashed, 0, 32);
                    Buffer.BlockCopy(witness.Pushes.First(), 0, hashed, 32, 32);
                    hashWitness = Hashes.Hash256(hashed);

                    if (!this.EqualsArray(hashWitness.ToBytes(), block.Transactions[0].Outputs[commitpos].ScriptPubKey.ToBytes(true).Skip(6).ToArray(), 32))
                    {
                        this.logger.LogTrace("(-)[WITNESS_MERKLE_MISMATCH]");
                        ConsensusErrors.BadWitnessMerkleMatch.Throw();
                    }

                    haveWitness = true;
                }
            }

            if (!haveWitness)
            {
                for (int i = 0; i < block.Transactions.Count; i++)
                {
                    if (block.Transactions[i].HasWitness)
                    {
                        this.logger.LogTrace("(-)[UNEXPECTED_WITNESS]");
                        ConsensusErrors.UnexpectedWitness.Throw();
                    }
                }
            }

            // After the coinbase witness nonce and commitment are verified,
            // we can check if the block weight passes (before we've checked the
            // coinbase witness, it would be possible for the weight to be too
            // large by filling up the coinbase witness, which doesn't change
            // the block hash, so we couldn't mark the block as permanently
            // failed).
            if (this.GetBlockWeight(block) > this.ConsensusOptions.MaxBlockWeight)
            {
                this.logger.LogTrace("(-)[BAD_BLOCK_WEIGHT]");
                ConsensusErrors.BadBlockWeight.Throw();
            }

            this.logger.LogTrace("(-)[OK]");
        }
Exemplo n.º 17
0
 public Bip322Signature(Script scriptSig, WitScript witness)
 {
     _scriptSig = scriptSig;
     Witness    = witness;
 }
Exemplo n.º 18
0
        internal PSBTInput(BitcoinStream stream, PSBT parent, uint index, TxIn input) : base(parent)
        {
            TxIn              = input;
            Index             = index;
            originalScriptSig = TxIn.ScriptSig ?? Script.Empty;
            originalWitScript = TxIn.WitScript ?? WitScript.Empty;
            byte[] k = new byte[0];
            byte[] v = new byte[0];
            try
            {
                stream.ReadWriteAsVarString(ref k);
            }
            catch (EndOfStreamException e)
            {
                throw new FormatException("Invalid PSBTInput. Failed to Parse key.", e);
            }
            while (k.Length != 0)
            {
                try
                {
                    stream.ReadWriteAsVarString(ref v);
                }
                catch (EndOfStreamException e)
                {
                    throw new FormatException("Invalid PSBTInput. Failed to parse key.", e);
                }
                switch (k.First())
                {
                case PSBTConstants.PSBT_IN_NON_WITNESS_UTXO:
                    if (k.Length != 1)
                    {
                        throw new FormatException("Invalid PSBTInput. Contains illegal value in key for NonWitnessUTXO");
                    }
                    if (non_witness_utxo != null)
                    {
                        throw new FormatException("Invalid PSBTInput. Duplicate non_witness_utxo");
                    }
                    non_witness_utxo = this.GetConsensusFactory().CreateTransaction();
                    non_witness_utxo.FromBytes(v);
                    break;

                case PSBTConstants.PSBT_IN_WITNESS_UTXO:
                    if (k.Length != 1)
                    {
                        throw new FormatException("Invalid PSBTInput. Contains illegal value in key for WitnessUTXO");
                    }
                    if (witness_utxo != null)
                    {
                        throw new FormatException("Invalid PSBTInput. Duplicate witness_utxo");
                    }
                    if (this.GetConsensusFactory().TryCreateNew <TxOut>(out var txout))
                    {
                        witness_utxo = txout;
                    }
                    else
                    {
                        witness_utxo = new TxOut();
                    }
                    witness_utxo.FromBytes(v);
                    break;

                case PSBTConstants.PSBT_IN_PARTIAL_SIG:
                    var pubkey = new PubKey(k.Skip(1).ToArray());
                    if (partial_sigs.ContainsKey(pubkey))
                    {
                        throw new FormatException("Invalid PSBTInput. Duplicate key for partial_sigs");
                    }
                    partial_sigs.Add(pubkey, new TransactionSignature(v));
                    break;

                case PSBTConstants.PSBT_IN_SIGHASH:
                    if (k.Length != 1)
                    {
                        throw new FormatException("Invalid PSBTInput. Contains illegal value in key for SigHash type");
                    }
                    if (!(sighash_type is null))
                    {
                        throw new FormatException("Invalid PSBTInput. Duplicate key for sighash_type");
                    }
                    if (v.Length != 4)
                    {
                        throw new FormatException("Invalid PSBTInput. SigHash Type is not 4 byte");
                    }
                    var value = Utils.ToUInt32(v, 0, true);
                    if (!Enum.IsDefined(typeof(SigHash), value))
                    {
                        throw new FormatException($"Invalid PSBTInput Unknown SigHash Type {value}");
                    }
                    sighash_type = (SigHash)value;
                    break;

                case PSBTConstants.PSBT_IN_REDEEMSCRIPT:
                    if (k.Length != 1)
                    {
                        throw new FormatException("Invalid PSBTInput. Contains illegal value in key for redeem script");
                    }
                    if (redeem_script != null)
                    {
                        throw new FormatException("Invalid PSBTInput. Duplicate key for redeem_script");
                    }
                    redeem_script = Script.FromBytesUnsafe(v);
                    break;

                case PSBTConstants.PSBT_IN_WITNESSSCRIPT:
                    if (k.Length != 1)
                    {
                        throw new FormatException("Invalid PSBTInput. Contains illegal value in key for witness script");
                    }
                    if (witness_script != null)
                    {
                        throw new FormatException("Invalid PSBTInput. Duplicate key for redeem_script");
                    }
                    witness_script = Script.FromBytesUnsafe(v);
                    break;

                case PSBTConstants.PSBT_IN_BIP32_DERIVATION:
                    var pubkey2 = new PubKey(k.Skip(1).ToArray());
                    if (hd_keypaths.ContainsKey(pubkey2))
                    {
                        throw new FormatException("Invalid PSBTInput. Duplicate key for hd_keypaths");
                    }
                    var     masterFingerPrint = new HDFingerprint(v.Take(4).ToArray());
                    KeyPath path = KeyPath.FromBytes(v.Skip(4).ToArray());
                    hd_keypaths.Add(pubkey2, new RootedKeyPath(masterFingerPrint, path));
                    break;

                case PSBTConstants.PSBT_IN_SCRIPTSIG:
                    if (k.Length != 1)
                    {
                        throw new FormatException("Invalid PSBTInput. Contains illegal value in key for final scriptsig");
                    }
                    if (final_script_sig != null)
                    {
                        throw new FormatException("Invalid PSBTInput. Duplicate key for final_script_sig");
                    }
                    final_script_sig = Script.FromBytesUnsafe(v);
                    break;

                case PSBTConstants.PSBT_IN_SCRIPTWITNESS:
                    if (k.Length != 1)
                    {
                        throw new FormatException("Invalid PSBTInput. Contains illegal value in key for final script witness");
                    }
                    if (final_script_witness != null)
                    {
                        throw new FormatException("Invalid PSBTInput. Duplicate key for final_script_witness");
                    }
                    final_script_witness = new WitScript(v);
                    break;

                default:
                    if (unknown.ContainsKey(k))
                    {
                        throw new FormatException("Invalid PSBTInput. Duplicate key for unknown value");
                    }
                    unknown.Add(k, v);
                    break;
                }
                stream.ReadWriteAsVarString(ref k);
            }
        }
Exemplo n.º 19
0
        public async Task CanBuildTaprootSingleSigTransactions()
        {
            using (var nodeBuilder = NodeBuilderEx.Create())
            {
                var rpc = nodeBuilder.CreateNode().CreateRPCClient();
                nodeBuilder.StartAll();
                rpc.Generate(102);
                var                change             = new Key();
                var                rootKey            = new ExtKey();
                var                accountKeyPath     = new KeyPath("86'/0'/0'");
                var                accountRootKeyPath = new RootedKeyPath(rootKey.GetPublicKey().GetHDFingerPrint(), accountKeyPath);
                var                accountKey         = rootKey.Derive(accountKeyPath);
                var                key         = accountKey.Derive(new KeyPath("0/0")).PrivateKey;
                var                address     = key.PubKey.GetAddress(ScriptPubKeyType.TaprootBIP86, nodeBuilder.Network);
                var                destination = new Key();
                var                amount      = new Money(1, MoneyUnit.BTC);
                uint256            id          = null;
                Transaction        tx          = null;
                ICoin              coin        = null;
                TransactionBuilder builder     = null;
                var                rate        = new FeeRate(Money.Satoshis(1), 1);

                async Task RefreshCoin()
                {
                    id = await rpc.SendToAddressAsync(address, Money.Coins(1));

                    tx = await rpc.GetRawTransactionAsync(id);

                    coin    = tx.Outputs.AsCoins().Where(o => o.ScriptPubKey == address.ScriptPubKey).Single();
                    builder = Network.Main.CreateTransactionBuilder(0);
                }

                await RefreshCoin();

                var signedTx = builder
                               .AddCoins(coin)
                               .AddKeys(key)
                               .Send(destination, amount)
                               .SubtractFees()
                               .SetChange(change)
                               .SendEstimatedFees(rate)
                               .BuildTransaction(true);
                rpc.SendRawTransaction(signedTx);

                await RefreshCoin();

                // Let's try again, but this time with PSBT
                var psbt = builder
                           .AddCoins(coin)
                           .Send(destination, amount)
                           .SubtractFees()
                           .SetChange(change)
                           .SendEstimatedFees(rate)
                           .BuildPSBT(false);

                var tk = key.PubKey.GetTaprootFullPubKey();
                psbt.Inputs[0].HDTaprootKeyPaths.Add(tk.OutputKey, new TaprootKeyPath(accountRootKeyPath.Derive(KeyPath.Parse("0/0"))));
                psbt.SignAll(ScriptPubKeyType.TaprootBIP86, accountKey, accountRootKeyPath);

                // Check if we can roundtrip
                psbt = CanRoundtripPSBT(psbt);

                psbt.Finalize();
                rpc.SendRawTransaction(psbt.ExtractTransaction());

                // Let's try again, but this time with BuildPSBT(true)
                await RefreshCoin();

                psbt = builder
                       .AddCoins(coin)
                       .AddKeys(key)
                       .Send(destination, amount)
                       .SubtractFees()
                       .SetChange(change)
                       .SendEstimatedFees(rate)
                       .BuildPSBT(true);
                psbt.Finalize();
                rpc.SendRawTransaction(psbt.ExtractTransaction());

                // Let's try again, this time with a merkle root
                var merkleRoot = RandomUtils.GetUInt256();
                address = key.PubKey.GetTaprootFullPubKey(merkleRoot).GetAddress(nodeBuilder.Network);

                await RefreshCoin();

                psbt = builder
                       .AddCoins(coin)
                       .AddKeys(key.CreateTaprootKeyPair(merkleRoot))
                       .Send(destination, amount)
                       .SubtractFees()
                       .SetChange(change)
                       .SendEstimatedFees(rate)
                       .BuildPSBT(true);
                Assert.NotNull(psbt.Inputs[0].TaprootMerkleRoot);
                Assert.NotNull(psbt.Inputs[0].TaprootInternalKey);
                Assert.NotNull(psbt.Inputs[0].TaprootKeySignature);
                psbt = CanRoundtripPSBT(psbt);
                psbt.Finalize();
                rpc.SendRawTransaction(psbt.ExtractTransaction());

                // Can we sign the PSBT separately?
                await RefreshCoin();

                psbt = builder
                       .AddCoins(coin)
                       .Send(destination, amount)
                       .SubtractFees()
                       .SetChange(change)
                       .SendEstimatedFees(rate)
                       .BuildPSBT(false);

                var taprootKeyPair = key.CreateTaprootKeyPair(merkleRoot);
                psbt.Inputs[0].Sign(taprootKeyPair);
                Assert.NotNull(psbt.Inputs[0].TaprootMerkleRoot);
                Assert.NotNull(psbt.Inputs[0].TaprootInternalKey);
                Assert.NotNull(psbt.Inputs[0].TaprootKeySignature);

                // This line is useless, we just use it to test the PSBT roundtrip
                psbt.Inputs[0].HDTaprootKeyPaths.Add(taprootKeyPair.PubKey,
                                                     new TaprootKeyPath(RootedKeyPath.Parse("12345678/86'/0'/0'/0/0"),
                                                                        new uint256[] { RandomUtils.GetUInt256() }));
                psbt = CanRoundtripPSBT(psbt);
                psbt.Finalize();
                rpc.SendRawTransaction(psbt.ExtractTransaction());

                // Can we sign the transaction separately?
                await RefreshCoin();

                var coin1 = coin;
                await RefreshCoin();

                var coin2 = coin;
                builder  = Network.Main.CreateTransactionBuilder(0);
                signedTx = builder
                           .AddCoins(coin1, coin2)
                           .Send(destination, amount)
                           .SubtractFees()
                           .SetChange(change)
                           .SendEstimatedFees(rate)
                           .BuildTransaction(false);
                var unsignedTx = signedTx.Clone();
                builder = Network.Main.CreateTransactionBuilder(0);
                builder.AddKeys(key.CreateTaprootKeyPair(merkleRoot));
                builder.AddCoins(coin1);
                var ex = Assert.Throws <InvalidOperationException>(() => builder.SignTransactionInPlace(signedTx));
                Assert.Contains("taproot", ex.Message);
                builder.AddCoin(coin2);
                builder.SignTransactionInPlace(signedTx);
                Assert.True(!WitScript.IsNullOrEmpty(signedTx.Inputs.FindIndexedInput(coin2.Outpoint).WitScript));
                // Another solution is to set the precomputed transaction data.
                signedTx = unsignedTx;
                builder  = Network.Main.CreateTransactionBuilder(0);
                builder.AddKeys(key.CreateTaprootKeyPair(merkleRoot));
                builder.AddCoins(coin2);
                builder.SetSigningOptions(new SigningOptions()
                {
                    PrecomputedTransactionData = signedTx.PrecomputeTransactionData(new ICoin[] { coin1, coin2 })
                });
                builder.SignTransactionInPlace(signedTx);
                Assert.True(!WitScript.IsNullOrEmpty(signedTx.Inputs.FindIndexedInput(coin2.Outpoint).WitScript));


                // Let's check if we estimate precisely the size of a taproot transaction.
                await RefreshCoin();

                signedTx = builder
                           .AddCoins(coin)
                           .AddKeys(key.CreateTaprootKeyPair(merkleRoot))
                           .Send(destination, amount)
                           .SubtractFees()
                           .SetChange(change)
                           .SendEstimatedFees(rate)
                           .BuildTransaction(false);
                var actualvsize = builder.EstimateSize(signedTx, true);
                builder.SignTransactionInPlace(signedTx);
                var expectedvsize = signedTx.GetVirtualSize();
                // The estimator can't assume the sighash to be default
                // for all inputs, so we likely overestimate 1 bytes per input
                Assert.Equal(expectedvsize, actualvsize - 1);
            }
        }
        public async Task <IActionResult> PostSignaturesAsync([FromQuery] string uniqueId, [FromQuery] long roundId, [FromBody] IDictionary <int, string> signatures)
        {
            if (roundId <= 0 ||
                signatures == null ||
                !signatures.Any() ||
                signatures.Any(x => x.Key < 0 || string.IsNullOrWhiteSpace(x.Value)) ||
                !ModelState.IsValid)
            {
                return(BadRequest());
            }

            (CcjRound round, Alice alice) = GetRunningRoundAndAliceOrFailureResponse(roundId, uniqueId, out IActionResult returnFailureResponse);
            if (returnFailureResponse != null)
            {
                return(returnFailureResponse);
            }

            // Check if Alice provided signature to all her inputs.
            if (signatures.Count != alice.Inputs.Count())
            {
                return(BadRequest("Alice did not provide enough witnesses."));
            }

            CcjRoundPhase phase = round.Phase;

            switch (phase)
            {
            case CcjRoundPhase.Signing:
            {
                using (await SigningLock.LockAsync())
                {
                    foreach (var signaturePair in signatures)
                    {
                        int       index   = signaturePair.Key;
                        WitScript witness = null;
                        try
                        {
                            witness = new WitScript(signaturePair.Value);
                        }
                        catch (Exception ex)
                        {
                            return(BadRequest($"Malformed witness is provided. Details: {ex.Message}"));
                        }
                        int maxIndex = round.UnsignedCoinJoin.Inputs.Count - 1;
                        if (maxIndex < index)
                        {
                            return(BadRequest($"Index out of range. Maximum value: {maxIndex}. Provided value: {index}"));
                        }

                        // Check duplicates.
                        if (round.SignedCoinJoin.Inputs[index].HasWitness())
                        {
                            return(BadRequest($"Input is already signed."));
                        }

                        // Verify witness.
                        var cjCopy = Transaction.Parse(round.UnsignedCoinJoin.ToHex(), Network);
                        cjCopy.Inputs[index].WitScript = witness;
                        TxOut output = alice.Inputs.Single(x => x.OutPoint == cjCopy.Inputs[index].PrevOut).Output;
                        if (!Script.VerifyScript(output.ScriptPubKey, cjCopy, index, output.Value, ScriptVerify.Standard, SigHash.All))
                        {
                            return(BadRequest($"Invalid witness is provided."));
                        }

                        // Finally add it to our CJ.
                        round.SignedCoinJoin.Inputs[index].WitScript = witness;
                    }

                    alice.State = AliceState.SignedCoinJoin;

                    await round.BroadcastCoinJoinIfFullySignedAsync();
                }

                return(NoContent());
            }

            default:
            {
                return(Conflict($"CoinJoin can only be requested from Signing phase. Current phase: {phase}."));
            }
            }
        }
Exemplo n.º 21
0
        /// <inheritdoc />
        /// <exception cref="ConsensusErrors.BadWitnessNonceSize">The witness nonce size is invalid.</exception>
        /// <exception cref="ConsensusErrors.BadWitnessMerkleMatch">The witness merkle commitment does not match the computed commitment.</exception>
        /// <exception cref="ConsensusErrors.UnexpectedWitness">The block does not expect witness transactions but contains a witness transaction.</exception>
        public override Task RunAsync(RuleContext context)
        {
            DeploymentFlags deploymentFlags = context.Flags;
            Block           block           = context.BlockValidationContext.Block;

            // Validation for witness commitments.
            // * We compute the witness hash (which is the hash including witnesses) of all the block's transactions, except the
            //   coinbase (where 0x0000....0000 is used instead).
            // * The coinbase scriptWitness is a stack of a single 32-byte vector, containing a witness nonce (unconstrained).
            // * We build a merkle tree with all those witness hashes as leaves (similar to the hashMerkleRoot in the block header).
            // * There must be at least one output whose scriptPubKey is a single 36-byte push, the first 4 bytes of which are
            //   {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness nonce). In case there are
            //   multiple, the last one is used.
            bool fHaveWitness = false;

            if (deploymentFlags.ScriptFlags.HasFlag(ScriptVerify.Witness))
            {
                int commitpos = this.GetWitnessCommitmentIndex(block);
                if (commitpos != -1)
                {
                    uint256 hashWitness = BlockWitnessMerkleRoot(block, out bool malleated);

                    // The malleation check is ignored; as the transaction tree itself
                    // already does not permit it, it is impossible to trigger in the
                    // witness tree.
                    WitScript witness = block.Transactions[0].Inputs[0].WitScript;
                    if ((witness.PushCount != 1) || (witness.Pushes.First().Length != 32))
                    {
                        this.Logger.LogTrace("(-)[BAD_WITNESS_NONCE_SIZE]");
                        ConsensusErrors.BadWitnessNonceSize.Throw();
                    }

                    byte[] hashed = new byte[64];
                    Buffer.BlockCopy(hashWitness.ToBytes(), 0, hashed, 0, 32);
                    Buffer.BlockCopy(witness.Pushes.First(), 0, hashed, 32, 32);
                    hashWitness = Hashes.Hash256(hashed);

                    if (!this.EqualsArray(hashWitness.ToBytes(), block.Transactions[0].Outputs[commitpos].ScriptPubKey.ToBytes(true).Skip(6).ToArray(), 32))
                    {
                        this.Logger.LogTrace("(-)[WITNESS_MERKLE_MISMATCH]");
                        ConsensusErrors.BadWitnessMerkleMatch.Throw();
                    }

                    fHaveWitness = true;
                }
            }

            if (!fHaveWitness)
            {
                for (int i = 0; i < block.Transactions.Count; i++)
                {
                    if (block.Transactions[i].HasWitness)
                    {
                        this.Logger.LogTrace("(-)[UNEXPECTED_WITNESS]");
                        ConsensusErrors.UnexpectedWitness.Throw();
                    }
                }
            }

            return(Task.CompletedTask);
        }
 public static TxDestination GetSigner(WitScript witScript)
 {
     if(witScript == WitScript.Empty)
         return null;
     var parameters = PayToWitPubKeyHashTemplate.Instance.ExtractWitScriptParameters(witScript);
     if(parameters != null)
         return parameters.PublicKey.WitHash;
     return Script.FromBytesUnsafe(witScript.GetUnsafePush(witScript.PushCount - 1)).WitHash;
 }
Exemplo n.º 23
0
 private static TxIn AttachWitScript(TxIn txIn, WitScript wit)
 {
     txIn.WitScript = wit;
     return(txIn);
 }
Exemplo n.º 24
0
 public InputWitnessPair(OutPoint input, WitScript witness)
 {
     Input   = input;
     Witness = witness;
 }
Exemplo n.º 25
0
            internal void ReadWrite(BitcoinStream stream)
            {
                for (int i = 0; i < _Inputs.Count; i++)
                {
                    if (stream.Serializing)
                    {
                        var bytes = ((ElementsTxIn)_Inputs[i]).IssuanceAmountRangeProof;
                        stream.ReadWriteAsVarString(ref bytes);


                        bytes = ((ElementsTxIn)_Inputs[i]).InflationKeysRangeProof;
                        stream.ReadWriteAsVarString(ref bytes);

                        bytes = (_Inputs[i].WitScript ?? WitScript.Empty).ToBytes();
                        stream.ReadWrite(ref bytes);

                        bytes = (((ElementsTxIn)_Inputs[i]).PeginWitScript ?? WitScript.Empty).ToBytes();
                        stream.ReadWrite(ref bytes);
                    }
                    else
                    {
                        byte[] bytes = null;
                        stream.ReadWriteAsVarString(ref bytes);
                        ((ElementsTxIn)_Inputs[i]).IssuanceAmountRangeProof = bytes;

                        bytes = null;
                        stream.ReadWriteAsVarString(ref bytes);
                        ((ElementsTxIn)_Inputs[i]).InflationKeysRangeProof = bytes;

                        ((ElementsTxIn)_Inputs[i]).WitScript = WitScript.Load(stream);

                        ((ElementsTxIn)_Inputs[i]).PeginWitScript = WitScript.Load(stream);
                    }
                }

                for (int i = 0; i < _Outputs.Count; i++)
                {
                    if (stream.Serializing)
                    {
                        var bytes = ((ElementsTxOut)_Outputs[i]).SurjectionProof;
                        stream.ReadWriteAsVarString(ref bytes);

                        bytes = ((ElementsTxOut)_Outputs[i]).RangeProof;
                        stream.ReadWriteAsVarString(ref bytes);
                    }
                    else
                    {
                        byte[] bytes = null;
                        stream.ReadWriteAsVarString(ref bytes);
                        ((ElementsTxOut)_Outputs[i]).SurjectionProof = bytes;

                        bytes = null;
                        stream.ReadWriteAsVarString(ref bytes);
                        ((ElementsTxOut)_Outputs[i]).RangeProof = bytes;
                    }
                }

                if (IsNull())
                {
                    throw new FormatException("Superfluous witness record");
                }
            }
Exemplo n.º 26
0
        internal void Combine(PSBTInput other)
        {
            if (this.IsFinalized())
            {
                return;
            }

            foreach (var uk in other.unknown)
            {
                unknown.TryAdd(uk.Key, uk.Value);
            }


            if (other.final_script_sig != null)
            {
                final_script_sig = other.final_script_sig;
            }

            if (other.final_script_witness != null)
            {
                final_script_witness = other.final_script_witness;
            }
            if (IsFinalized())
            {
                ClearForFinalize();
                return;
            }

            if (non_witness_utxo == null && other.non_witness_utxo != null)
            {
                non_witness_utxo = other.non_witness_utxo;
            }

            if (witness_utxo == null && other.witness_utxo != null)
            {
                non_witness_utxo = other.non_witness_utxo;
            }

            if (sighash_type == 0 && other.sighash_type > 0)
            {
                sighash_type = other.sighash_type;
            }

            if (redeem_script == null && other.redeem_script != null)
            {
                redeem_script = other.redeem_script;
            }

            if (witness_script == null && other.witness_script != null)
            {
                witness_script = other.witness_script;
            }

            foreach (var sig in other.partial_sigs)
            {
                partial_sigs.TryAdd(sig.Key, sig.Value);
            }

            foreach (var keyPath in other.hd_keypaths)
            {
                hd_keypaths.TryAdd(keyPath.Key, keyPath.Value);
            }
        }
Exemplo n.º 27
0
 private bool CheckWitScriptCore(WitScript witScript)
 {
     return(witScript.PushCount == 2 &&
            ((witScript[0].Length == 1 && witScript[0][0] == 0) || (TransactionSignature.IsValid(witScript[0], ScriptVerify.None))) &&
            PubKey.Check(witScript[1], false));
 }
Exemplo n.º 28
0
        public override void ExtractExistingSignatures(InputSigningContext inputSigningContext)
        {
            if (inputSigningContext.OriginalTxIn is null || inputSigningContext.TransactionContext.Transaction is null)
            {
                return;
            }
            var scriptSig      = inputSigningContext.OriginalTxIn.ScriptSig;
            var witScript      = inputSigningContext.OriginalTxIn.WitScript;
            var multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(inputSigningContext.Coin.GetScriptCode());
            var txIn           = inputSigningContext.Input;
            var scriptPubKey   = inputSigningContext.Coin.GetScriptCode();

            bool          hasRedeem;
            List <byte[]> sigs;

            if (inputSigningContext.Coin is ScriptCoin scriptCoin)
            {
                hasRedeem = true;
                if (scriptCoin.RedeemType == RedeemType.P2SH)
                {
                    if (Script.IsNullOrEmpty(inputSigningContext.OriginalTxIn.ScriptSig))
                    {
                        return;
                    }
                    sigs = scriptSig.ToOps().Select(s => s.PushData).ToList();
                }
                else                 // if (scriptCoin.RedeemType == RedeemType.WitnessV0)
                {
                    if (WitScript.IsNullOrEmpty(inputSigningContext.OriginalTxIn.WitScript))
                    {
                        return;
                    }
                    sigs = witScript.Pushes.ToList();
                }
            }
            else
            {
                hasRedeem = false;
                sigs      = scriptSig.ToOps().Select(s => s.PushData).ToList();
            }
            // At least leading 0, pk count and the redeem
            if (sigs.Count < 2 + (hasRedeem ? 1 : 0))
            {
                return;
            }
            if (!(sigs[0]?.Length is 0))
            {
                return;
            }
            sigs.RemoveAt(0);             // Remove leading 0
            if (hasRedeem)
            {
                sigs.RemoveAt(sigs.Count - 1);                 // Remove the redeem
            }
            int pkIndex = 0;

            for (int i = 0; i < sigs.Count && pkIndex < multiSigParams.PubKeys.Length; i++)
            {
                var sig = sigs[i];
                var pk  = multiSigParams.PubKeys[pkIndex];
                if (sig.Length is 0)
                {
                    pkIndex++;
                }
                else
                {
                    try
                    {
                        var txsig = new TransactionSignature(sig);
                        var hash  = inputSigningContext.TransactionContext
                                    .Transaction
                                    .Inputs.FindIndexedInput(inputSigningContext.Coin.Outpoint)
                                    .GetSignatureHash(inputSigningContext.Coin, txsig.SigHash, inputSigningContext.TransactionContext.SigningOptions.PrecomputedTransactionData);
                        while (!pk.Verify(hash, txsig.Signature))
                        {
                            pkIndex++;
                            if (pkIndex >= multiSigParams.PubKeys.Length)
                            {
                                goto end;
                            }
                            pk = multiSigParams.PubKeys[pkIndex];
                        }
                        txIn.PartialSigs.TryAdd(pk, txsig);
                        pkIndex++;
                    }
                    catch { }
                }
            }
            end:;
        }
Exemplo n.º 29
0
		public PayToWitPubkeyHashScriptSigParameters ExtractWitScriptParameters(WitScript witScript)
		{
			if(!CheckWitScriptCore(witScript))
				return null;
			try
			{
				return new PayToWitPubkeyHashScriptSigParameters()
				{
					TransactionSignature = (witScript[0].Length == 1 && witScript[0][0] == 0) ? null : new TransactionSignature(witScript[0]),
					PublicKey = new PubKey(witScript[1], true),
				};
			}
			catch(FormatException)
			{
				return null;
			}
		}
Exemplo n.º 30
0
        public async Task <IActionResult> PostSignaturesAsync([FromQuery] string uniqueId, [FromQuery] long roundId, [FromBody] IDictionary <int, string> signatures)
        {
            if (roundId <= 0 ||
                signatures == null ||
                signatures.Count() <= 0 ||
                signatures.Any(x => x.Key < 0 || string.IsNullOrWhiteSpace(x.Value)) ||
                !ModelState.IsValid)
            {
                return(BadRequest());
            }

            Guid uniqueIdGuid = CheckUniqueId(uniqueId, out IActionResult returnFailureResponse);

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

            CcjRound round = Coordinator.TryGetRound(roundId);

            if (round == null)
            {
                return(NotFound("Round not found."));
            }

            Alice alice = round.TryGetAliceBy(uniqueIdGuid);

            if (alice == null)
            {
                return(NotFound("Alice not found."));
            }

            // Check if Alice provided signature to all her inputs.
            if (signatures.Count != alice.Inputs.Count())
            {
                return(BadRequest("Alice did not provide enough witnesses."));
            }

            if (round.Status != CcjRoundStatus.Running)
            {
                return(Gone("Round is not running."));
            }

            CcjRoundPhase phase = round.Phase;

            switch (phase)
            {
            case CcjRoundPhase.Signing:
            {
                using (await SigningLock.LockAsync())
                {
                    foreach (var signaturePair in signatures)
                    {
                        int       index   = signaturePair.Key;
                        WitScript witness = null;
                        try
                        {
                            witness = new WitScript(signaturePair.Value);
                        }
                        catch (Exception ex)
                        {
                            return(BadRequest($"Malformed witness is provided. Details: {ex.Message}"));
                        }
                        int maxIndex = round.UnsignedCoinJoin.Inputs.Count - 1;
                        if (maxIndex < index)
                        {
                            return(BadRequest($"Index out of range. Maximum value: {maxIndex}. Provided value: {index}"));
                        }

                        // Check duplicates.
                        if (!string.IsNullOrWhiteSpace(round.SignedCoinJoin.Inputs[index].WitScript?.ToString()))                                        // Not sure why WitScript?.ToString() is needed, there was something wrong in previous HiddenWallet version if I didn't do this.
                        {
                            return(BadRequest($"Input is already signed."));
                        }

                        // Verify witness.
                        var cjCopy = new Transaction(round.UnsignedCoinJoin.ToHex());
                        cjCopy.Inputs[index].WitScript = witness;
                        TxOut output = alice.Inputs.Single(x => x.OutPoint == cjCopy.Inputs[index].PrevOut).Output;
                        if (!Script.VerifyScript(output.ScriptPubKey, cjCopy, index, output.Value, ScriptVerify.Standard, SigHash.All))
                        {
                            return(BadRequest($"Invalid witness is provided."));
                        }

                        // Finally add it to our CJ.
                        round.SignedCoinJoin.Inputs[index].WitScript = witness;
                    }

                    alice.State = AliceState.SignedCoinJoin;

                    await round.BroadcastCoinJoinIfFullySignedAsync();
                }

                return(NoContent());
            }

            default:
            {
                return(Conflict($"CoinJoin can only be requested from Signing phase. Current phase: {phase}."));
            }
            }
        }
Exemplo n.º 31
0
		/// <summary>
		/// Extract witness redeem from WitScript
		/// </summary>
		/// <param name="witScript">Witscript to extract information from</param>
		/// <param name="expectedScriptId">Expected redeem hash</param>
		/// <returns>The witness redeem</returns>
		public Script ExtractWitScriptParameters(WitScript witScript, WitScriptId expectedScriptId = null)
		{
			if(witScript.PushCount == 0)
				return null;
			var last = witScript.GetUnsafePush(witScript.PushCount - 1);
			Script redeem = new Script(last);
			if(expectedScriptId != null)
			{
				if(expectedScriptId != redeem.WitHash)
					return null;
			}
			return redeem;
		}
Exemplo n.º 32
0
        public override void ReadWrite(BitcoinStream stream)
        {
            var fAllowWitness = stream.TransactionOptions.HasFlag(TransactionOptions.Witness) && stream.ProtocolCapabilities.SupportWitness;
            // Detect dynamic federation block serialization using "HF bit",
            // or the signed bit which is invalid in Bitcoin
            var isDynamic = false;
            int version   = 0;

            if (!stream.Serializing)
            {
                stream.ReadWrite(ref version);
                isDynamic = version < 0;
                nVersion  = ~DYNAFED_HF_MASK & version;
            }
            else
            {
                version = nVersion;
                if (!DynaFedParams.IsNull)
                {
                    version  |= DYNAFED_HF_MASK;
                    isDynamic = true;
                }
                stream.ReadWrite(ref version);
            }

            if (isDynamic)
            {
                stream.ReadWrite(ref hashPrevBlock);
                stream.ReadWrite(ref hashMerkleRoot);
                stream.ReadWrite(ref nTime);
                stream.ReadWrite(ref _nHeight);
                stream.ReadWrite(ref DynaFedParams);
                if (stream.Type != SerializationType.Hash && fAllowWitness)
                {
                    if (stream.Serializing)
                    {
                        SignBlockWitness.WriteToStream(stream);
                    }
                    else
                    {
                        SignBlockWitness = WitScript.Load(stream);
                    }
                }
                stream.ReadWrite(ref hashMerkleRoot);
                stream.ReadWrite(ref nTime);

                if (ElementsParams <TNetwork> .BlockHeightInHeader)
                {
                    stream.ReadWrite(ref _nHeight);
                }

                if (ElementsParams <TNetwork> .SignedBlocks)
                {
                    stream.ReadWrite(ref _Proof);
                }
                else
                {
                    stream.ReadWrite(ref nBits);
                    stream.ReadWrite(ref nNonce);
                }
            }
            else
            {
                stream.ReadWrite(ref hashPrevBlock);
                stream.ReadWrite(ref hashMerkleRoot);
                stream.ReadWrite(ref nTime);
                stream.ReadWrite(ref _nHeight);
                stream.ReadWrite(ref _Proof);
            }
        }
        /// <summary>
        /// Whether transaction is witness standard.
        /// <seealso cref="https://github.com/bitcoin/bitcoin/blob/aa624b61c928295c27ffbb4d27be582f5aa31b56/src/policy/policy.cpp#L196"/>
        /// </summary>
        /// <param name="tx">Transaction to verify.</param>
        /// <param name="mapInputs">Map of previous transactions that have outputs we're spending.</param>
        /// <returns>Whether transaction is witness standard.</returns>
        private bool IsWitnessStandard(Transaction tx, MempoolCoinView mapInputs)
        {
            if (tx.IsCoinBase)
            {
                this.logger.LogTrace("(-)[IS_COINBASE]:true");
                return(true); // Coinbases are skipped.
            }

            foreach (TxIn input in tx.Inputs)
            {
                // We don't care if witness for this input is empty, since it must not be bloated.
                // If the script is invalid without witness, it would be caught sooner or later during validation.
                if (input.WitScriptEmpty)
                {
                    continue;
                }

                TxOut prev = mapInputs.GetOutputFor(input);

                // Get the scriptPubKey corresponding to this input.
                Script prevScript = prev.ScriptPubKey;
                if (prevScript.IsPayToScriptHash(this.network))
                {
                    // If the scriptPubKey is P2SH, we try to extract the redeemScript casually by converting the scriptSig
                    // into a stack. We do not check IsPushOnly nor compare the hash as these will be done later anyway.
                    // If the check fails at this stage, we know that this txid must be a bad one.
                    PayToScriptHashSigParameters sigParams = PayToScriptHashTemplate.Instance.ExtractScriptSigParameters(this.network, input.ScriptSig);
                    if (sigParams == null || sigParams.RedeemScript == null)
                    {
                        this.logger.LogTrace("(-)[BAD_TXID]:false");
                        return(false);
                    }

                    prevScript = sigParams.RedeemScript;
                }

                // Non-witness program must not be associated with any witness.
                if (!prevScript.IsWitness(this.network))
                {
                    this.logger.LogTrace("(-)[WITNESS_MISMATCH]:false");
                    return(false);
                }

                // Check P2WSH standard limits.
                WitProgramParameters wit = PayToWitTemplate.Instance.ExtractScriptPubKeyParameters2(this.chainIndexer.Network, prevScript);
                if (wit == null)
                {
                    this.logger.LogTrace("(-)[BAD_WITNESS_PARAMS]:false");
                    return(false);
                }

                // Version 0 segregated witness program validation.
                if (wit.Version == 0 && wit.Program.Length == WitnessV0ScriptHashSize)
                {
                    WitScript witness = input.WitScript;

                    // Get P2WSH script from top of stack.
                    Script scriptPubKey = Script.FromBytesUnsafe(witness.GetUnsafePush(witness.PushCount - 1));

                    // Stack items are remainder of stack.
                    int sizeWitnessStack = witness.PushCount - 1;

                    // Get the witness stack items.
                    var stack = new List <byte[]>();
                    for (int i = 0; i < sizeWitnessStack; i++)
                    {
                        stack.Add(witness.GetUnsafePush(i));
                    }

                    // Validate P2WSH script isn't larger than max length.
                    if (scriptPubKey.ToBytes(true).Length > MaxStandardP2wshScriptSize)
                    {
                        this.logger.LogTrace("(-)[P2WSH_SCRIPT_SIZE]:false");
                        return(false);
                    }

                    // Validate number items in witness stack isn't larger than max.
                    if (sizeWitnessStack > MaxStandardP2wshStackItems)
                    {
                        this.logger.LogTrace("(-)[P2WSH_STACK_ITEMS]:false");
                        return(false);
                    }

                    // Validate size of each of the witness stack items.
                    for (int j = 0; j < sizeWitnessStack; j++)
                    {
                        if (stack[j].Length > MaxStandardP2wshStackItemSize)
                        {
                            this.logger.LogTrace("(-)[P2WSH_STACK_ITEM_SIZE]:false");
                            return(false);
                        }
                    }
                }
            }

            return(true);
        }
Exemplo n.º 34
0
 public InputWitnessPair(uint inputIndex, WitScript witness)
 {
     InputIndex = inputIndex;
     Witness    = witness;
 }