Beispiel #1
0
size_t validate_block::script_hash_signature_operations_count(
    const script& output_script, const script& input_script)
{
    if (output_script.type() != payment_type::script_hash)
        return count_script_sigops(output_script.operations(), true);
    if (input_script.operations().empty())
        return 0;
    script eval_script = parse_script(input_script.operations().back().data);
    return count_script_sigops(eval_script.operations(), true);
}
Beispiel #2
0
bool extract(payment_address& address, const script& scr)
{
    // Cast a data_chunk to a short_hash and set the address
    auto set_hash_data =
        [&address](payment_type pay_type, const data_chunk& raw_hash)
        {
            short_hash hash_data;
            BITCOIN_ASSERT(raw_hash.size() == hash_data.size());
            std::copy(raw_hash.begin(), raw_hash.end(), hash_data.begin());
            address.set(pay_type, hash_data);
        };
    const operation_stack& ops = scr.operations();
    payment_type pay_type = scr.type();
    switch (pay_type)
    {
        case payment_type::pubkey:
            BITCOIN_ASSERT(ops.size() == 2);
            set_public_key(address, ops[0].data);
            return true;

        case payment_type::pubkey_hash:
            BITCOIN_ASSERT(ops.size() == 5);
            set_hash_data(pay_type, ops[2].data);
            return true;

        case payment_type::script_hash:
            BITCOIN_ASSERT(ops.size() == 3);
            set_hash_data(pay_type, ops[1].data);
            return true;

        case payment_type::multisig:
            // Unimplemented...
            return false;

        case payment_type::pubkey_hash_sig:
            BITCOIN_ASSERT(ops.size() == 2);
            set_public_key(address, ops[1].data);
            return true;

        case payment_type::script_code_sig:
            // Should have at least 1 sig and the script code.
            BITCOIN_ASSERT(ops.size() > 1);
            set_script_hash(address,
                generate_ripemd_hash(ops.back().data));
            return true;

        default:
            return false;
    }
    // Should never happen!
    return false;
}
// Validate script consensus conformance based on flags provided.
static bool check_consensus(const script& prevout_script,
    const transaction& current_tx, size_t input_index,
    uint32_t options)
{
    BITCOIN_ASSERT(input_index <= max_uint32);
    BITCOIN_ASSERT(input_index < current_tx.inputs.size());
    const auto input_index32 = static_cast<uint32_t>(input_index);
    const auto bip16_enabled = ((options & validation_options::p2sh) != 0);

#ifdef WITH_CONSENSUS
    using namespace bc::consensus;
    const auto previous_output_script = prevout_script.to_data(false);
    data_chunk current_transaction = current_tx.to_data();

    const auto flags = (bip16_enabled ? verify_flags_p2sh : verify_flags_none);
    const auto result = verify_script(current_transaction.data(),
        current_transaction.size(), previous_output_script.data(),
        previous_output_script.size(), input_index32, flags);

    const auto valid = (result == verify_result::verify_result_eval_true);
#else
    // Copy the const prevout script so it can be run.
    auto previous_output_script = prevout_script;
    const auto& current_input_script = current_tx.inputs[input_index].script;

    const auto valid = script::verify(current_input_script,
        previous_output_script, current_tx, input_index32, bip16_enabled);
#endif

    if (!valid)
        log::warning(LOG_VALIDATE) << "Invalid transaction ["
        << encode_hash(current_tx.hash()) << "]";

    return valid;
}
Beispiel #4
0
bool is_stealth_script(const script& script)
{
    if (script.pattern() != chain::script_pattern::null_data)
        return false;

    BITCOIN_ASSERT(script.operations.size() == 2);
    const auto& data = script.operations[1].data;
    return (data.size() >= hash_size);
}
Beispiel #5
0
bool extract_input_address(
    payment_address& address, const script& input_script)
{
    const operation_stack& ops = input_script.operations();
    if (!input_has_pubkey(ops))
        return false;
    BITCOIN_ASSERT(ops.size() == 2);
    const data_chunk& pubkey = ops[1].data;
    if (!set_public_key(address, pubkey))
        return false;
    return true;
}
Beispiel #6
0
bool to_stealth_prefix(uint32_t& out_prefix, const script& script)
{
    if (!is_stealth_script(script))
        return false;

    // A stealth prefix is the full 32 bits (prefix to the hash).
    // A stealth filter is a leftmost substring of the stealth prefix.
    constexpr size_t size = binary::bits_per_block * sizeof(uint32_t);

    const auto script_hash = bitcoin_hash(script.to_data(false));
    out_prefix = from_little_endian_unsafe<uint32_t>(script_hash.begin());
    return true;
}
Beispiel #7
0
data_chunk save_script(const script& scr)
{
    data_chunk raw_script;
    for (operation op: scr.operations())
    {
        byte raw_byte = static_cast<byte>(op.code);
        if (op.code == opcode::special)
            raw_byte = op.data.size();
        raw_script.push_back(raw_byte);
        extend_data(raw_script, op.data);
    }
    return raw_script;
}
Beispiel #8
0
bool parse(script& result_script, const std::string& format)
{
    if (format.empty())
        return true;
    std::vector<std::string> tokens;
    boost::split(tokens, format, boost::is_any_of(" "));
    data_chunk raw_script;
    for (const auto& token: tokens)
        if (!parse_token(raw_script, token))
            return false;
    parse_token(raw_script, "ENDING");
    result_script = parse_script(raw_script);
    if (result_script.operations().empty())
        return false;
    return true;
}
// Validate script consensus conformance based on flags provided.
bool validate_transaction::check_consensus(const script& prevout_script,
    const transaction& current_tx, size_t input_index, uint32_t flags)
{
    BITCOIN_ASSERT(input_index <= max_uint32);
    BITCOIN_ASSERT(input_index < current_tx.inputs.size());
    const auto input_index32 = static_cast<uint32_t>(input_index);

#ifdef WITH_CONSENSUS
    using namespace bc::consensus;
    const auto previous_output_script = prevout_script.to_data(false);
    data_chunk current_transaction = current_tx.to_data();

    // Convert native flags to libbitcoin-consensus flags.
    uint32_t consensus_flags = verify_flags_none;

    if ((flags & script_context::bip16_enabled) != 0)
        consensus_flags |= verify_flags_p2sh;

    if ((flags & script_context::bip65_enabled) != 0)
        consensus_flags |= verify_flags_checklocktimeverify;

    if ((flags & script_context::bip66_enabled) != 0)
        consensus_flags |= verify_flags_dersig;

    const auto result = verify_script(current_transaction.data(),
        current_transaction.size(), previous_output_script.data(),
        previous_output_script.size(), input_index32, consensus_flags);

    const auto valid = (result == verify_result::verify_result_eval_true);
#else
    // Copy the const prevout script so it can be run.
    auto previous_output_script = prevout_script;
    const auto& current_input_script = current_tx.inputs[input_index].script;

    const auto valid = script::verify(current_input_script,
        previous_output_script, current_tx, input_index32, flags);
#endif

    if (!valid)
        log::warning(LOG_BLOCKCHAIN)
            << "Invalid transaction ["
            << encode_hash(current_tx.hash()) << "]";

    return valid;
}