Repository: bitcoin/bitcoin
File: src/test/script_tests.cpp (C++)

Code before:
    SignatureData data;
    data.MergeSignatureData(scriptSig1);
    data.MergeSignatureData(scriptSig2);
    ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(tx, 0, txout.nValue, SIGHASH_DEFAULT), txout.scriptPubKey, data);
    return data;
}

BOOST_AUTO_TEST_CASE(script_combineSigs)
{
    // Test the ProduceSignature's ability to combine signatures function
    FillableSigningProvider keystore;
    std::vector<CKey> keys;
    std::vector<CPubKey> pubkeys;
    for (int i = 0; i < 3; i++)
    {
        CKey key = GenerateRandomKey(/*compressed=*/i%2 == 1);
        keys.push_back(key);
        pubkeys.push_back(key.GetPubKey());
        BOOST_CHECK(keystore.AddKey(key));
    }

    CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(PKHash(keys[0].GetPubKey())));
    CMutableTransaction txTo = BuildSpendingTransaction(CScript(), CScriptWitness(), CTransaction(txFrom));
    CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
    SignatureData scriptSig;

    SignatureData empty;
    SignatureData combined = CombineSignatures(txFrom.vout[0], txTo, empty, empty);
    BOOST_CHECK(combined.scriptSig.empty());

    // Single signature case:
    SignatureData dummy;
    BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy)); // changes scriptSig
    scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
    combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
    BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
    combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
    BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
    SignatureData scriptSigCopy = scriptSig;
    // Signing again will give a different, valid signature:
    SignatureData dummy_b;
    BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy_b));
    scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
    combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);
    BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);

    // P2SH, single-signature case:
    CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
    BOOST_CHECK(keystore.AddCScript(pkSingle));
    scriptPubKey = GetScriptForDestination(ScriptHash(pkSingle));
    SignatureData dummy_c;

Review comment (suggestion):
nit in 3a9c80f7b4807e9abd9f2da36e8ee479ecf00d19:

`GetPubKey` does not need to be wrapped in `CPubKey{}`. You could just store a `dummy_pubkey` for all test cases to re-use.

Code after:
    std::vector<std::vector<uint8_t>> unused;
    return Solver(output_script, unused);
}

#define CHECK_SCRIPT_STATIC_SIZE(script, expected_size)                   \
    do {                                                                  \
        BOOST_CHECK_EQUAL((script).size(), (expected_size));              \
        BOOST_CHECK_EQUAL((script).capacity(), CScriptBase::STATIC_SIZE); \
        BOOST_CHECK_EQUAL((script).allocated_memory(), 0);                \
    } while (0)

#define CHECK_SCRIPT_DYNAMIC_SIZE(script, expected_size, expected_extra)                 \
    do {                                                                 \
        BOOST_CHECK_EQUAL((script).size(), (expected_size));             \
        BOOST_CHECK_EQUAL((script).capacity(), (expected_extra));         \
        BOOST_CHECK_EQUAL((script).allocated_memory(), (expected_extra)); \
    } while (0)

BOOST_AUTO_TEST_CASE(script_size_and_capacity_test)
{
    BOOST_CHECK_EQUAL(sizeof(CompressedScript), 40);
    BOOST_CHECK_EQUAL(sizeof(CScriptBase), 40);
    BOOST_CHECK_NE(sizeof(CScriptBase), sizeof(prevector<CScriptBase::STATIC_SIZE + 1, uint8_t>)); // CScriptBase size should be set to avoid wasting space in padding
    BOOST_CHECK_EQUAL(sizeof(CScript), 40);
    BOOST_CHECK_EQUAL(sizeof(CTxOut), 48);

    CKey dummy_key;
    dummy_key.MakeNewKey(/*fCompressed=*/true);
    const CPubKey dummy_pubkey{dummy_key.GetPubKey()};

    // Small OP_RETURN has direct allocation
    {
        const auto script{CScript() << OP_RETURN << std::vector<uint8_t>(10, 0xaa)};
        BOOST_CHECK_EQUAL(GetTxoutType(script), TxoutType::NULL_DATA);
        CHECK_SCRIPT_STATIC_SIZE(script, 12);
    }

    // P2WPKH has direct allocation
    {
        const auto script{GetScriptForDestination(WitnessV0KeyHash{PKHash{dummy_pubkey}})};
        BOOST_CHECK_EQUAL(GetTxoutType(script), TxoutType::WITNESS_V0_KEYHASH);
        CHECK_SCRIPT_STATIC_SIZE(script, 22);
    }

    // P2SH has direct allocation
    {
        const auto script{GetScriptForDestination(ScriptHash{CScript{} << OP_TRUE})};
        BOOST_CHECK(script.IsPayToScriptHash());
        CHECK_SCRIPT_STATIC_SIZE(script, 23);
    }