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); }
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; }
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); }
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; }
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; }
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; }
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; }