mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-21 15:50:07 +01:00
Merge bitcoin/bitcoin#34296: refactor: [move-only] Merge core_io module, remove from libkernel
faf07bd1abdoc: Fix typo found by LLM (MarcoFalke)faf66673acrefactor: [move-only] Merge core_io module (MarcoFalke)fa6947f491kernel: Remove unused core_read.cpp from kernel (MarcoFalke) Pull request description: Currently the core_io module is split across two translation units. This will confuse code readers and tooling about the real state of the module. Fix that by merging the module and removing the mapping workarounds. Also, remove the module from the kernel lib, because it is not used there: The kernel does not use any json or string parsing or formatting. ACKs for top commit: hebasto: re-ACKfaf07bd1ab, only rebased since my recent [review](https://github.com/bitcoin/bitcoin/pull/34296#pullrequestreview-3675359502). sedited: Re-ACKfaf07bd1abstickies-v: ACKfaf07bd1abTree-SHA512: 3f5d91f1a4cb86dfe329b28ff31e93d65f2f0659a6f6f2de22ca6fb65056fb818ae369ef0ad773d4f5b92f63891a7a9450246377d8e14c34bc43f3deee0554cb
This commit is contained in:
@@ -215,7 +215,7 @@ fi
|
||||
|
||||
if [[ "${RUN_IWYU}" == true ]]; then
|
||||
# TODO: Consider enforcing IWYU across the entire codebase.
|
||||
FILES_WITH_ENFORCED_IWYU="/src/((crypto|index|kernel)/.*\\.cpp|node/blockstorage.cpp|node/utxo_snapshot.cpp|core_read.cpp|signet.cpp)"
|
||||
FILES_WITH_ENFORCED_IWYU="/src/((crypto|index|kernel)/.*\\.cpp|node/blockstorage.cpp|node/utxo_snapshot.cpp|core_io.cpp|signet.cpp)"
|
||||
jq --arg patterns "$FILES_WITH_ENFORCED_IWYU" 'map(select(.file | test($patterns)))' "${BASE_BUILD_DIR}/compile_commands.json" > "${BASE_BUILD_DIR}/compile_commands_iwyu_errors.json"
|
||||
jq --arg patterns "$FILES_WITH_ENFORCED_IWYU" 'map(select(.file | test($patterns) | not))' "${BASE_BUILD_DIR}/compile_commands.json" > "${BASE_BUILD_DIR}/compile_commands_iwyu_warnings.json"
|
||||
|
||||
|
||||
@@ -6,11 +6,6 @@
|
||||
import sys
|
||||
import re
|
||||
|
||||
MAPPING = {
|
||||
'core_read.cpp': 'core_io.cpp',
|
||||
'core_write.cpp': 'core_io.cpp',
|
||||
}
|
||||
|
||||
# Directories with header-based modules, where the assumption that .cpp files
|
||||
# define functions and variables declared in corresponding .h files is
|
||||
# incorrect.
|
||||
@@ -19,8 +14,6 @@ HEADER_MODULE_PATHS = [
|
||||
]
|
||||
|
||||
def module_name(path):
|
||||
if path in MAPPING:
|
||||
path = MAPPING[path]
|
||||
if any(path.startswith(dirpath) for dirpath in HEADER_MODULE_PATHS):
|
||||
return path
|
||||
if path.endswith(".h"):
|
||||
|
||||
@@ -106,8 +106,7 @@ add_library(bitcoin_common STATIC EXCLUDE_FROM_ALL
|
||||
common/system.cpp
|
||||
common/url.cpp
|
||||
compressor.cpp
|
||||
core_read.cpp
|
||||
core_write.cpp
|
||||
core_io.cpp
|
||||
deploymentinfo.cpp
|
||||
external_signer.cpp
|
||||
init/common.cpp
|
||||
|
||||
@@ -4,25 +4,282 @@
|
||||
|
||||
#include <core_io.h>
|
||||
|
||||
#include <common/system.h>
|
||||
#include <addresstype.h>
|
||||
#include <coins.h>
|
||||
#include <consensus/amount.h>
|
||||
#include <consensus/consensus.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <key_io.h>
|
||||
#include <primitives/block.h> // IWYU pragma: keep
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/descriptor.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/script.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/solver.h>
|
||||
#include <serialize.h>
|
||||
#include <streams.h>
|
||||
#include <tinyformat.h>
|
||||
#include <uint256.h>
|
||||
#include <undo.h>
|
||||
#include <univalue.h>
|
||||
#include <util/check.h>
|
||||
#include <util/result.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/string.h>
|
||||
#include <util/translation.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using util::SplitString;
|
||||
|
||||
namespace {
|
||||
class OpCodeParser
|
||||
{
|
||||
private:
|
||||
std::map<std::string, opcodetype> mapOpNames;
|
||||
|
||||
public:
|
||||
OpCodeParser()
|
||||
{
|
||||
for (unsigned int op = 0; op <= MAX_OPCODE; ++op) {
|
||||
// Allow OP_RESERVED to get into mapOpNames
|
||||
if (op < OP_NOP && op != OP_RESERVED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string strName = GetOpName(static_cast<opcodetype>(op));
|
||||
if (strName == "OP_UNKNOWN") {
|
||||
continue;
|
||||
}
|
||||
mapOpNames[strName] = static_cast<opcodetype>(op);
|
||||
// Convenience: OP_ADD and just ADD are both recognized:
|
||||
if (strName.starts_with("OP_")) {
|
||||
mapOpNames[strName.substr(3)] = static_cast<opcodetype>(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
opcodetype Parse(const std::string& s) const
|
||||
{
|
||||
auto it = mapOpNames.find(s);
|
||||
if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode");
|
||||
return it->second;
|
||||
}
|
||||
};
|
||||
|
||||
opcodetype ParseOpCode(const std::string& s)
|
||||
{
|
||||
static const OpCodeParser ocp;
|
||||
return ocp.Parse(s);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CScript ParseScript(const std::string& s)
|
||||
{
|
||||
CScript result;
|
||||
|
||||
std::vector<std::string> words = SplitString(s, " \t\n");
|
||||
|
||||
for (const std::string& w : words) {
|
||||
if (w.empty()) {
|
||||
// Empty string, ignore. (SplitString doesn't combine multiple separators)
|
||||
} else if (std::all_of(w.begin(), w.end(), ::IsDigit) ||
|
||||
(w.front() == '-' && w.size() > 1 && std::all_of(w.begin() + 1, w.end(), ::IsDigit)))
|
||||
{
|
||||
// Number
|
||||
const auto num{ToIntegral<int64_t>(w)};
|
||||
|
||||
// limit the range of numbers ParseScript accepts in decimal
|
||||
// since numbers outside -0xFFFFFFFF...0xFFFFFFFF are illegal in scripts
|
||||
if (!num.has_value() || num > int64_t{0xffffffff} || num < -1 * int64_t{0xffffffff}) {
|
||||
throw std::runtime_error("script parse error: decimal numeric value only allowed in the "
|
||||
"range -0xFFFFFFFF...0xFFFFFFFF");
|
||||
}
|
||||
|
||||
result << num.value();
|
||||
} else if (w.starts_with("0x") && w.size() > 2 && IsHex(std::string(w.begin() + 2, w.end()))) {
|
||||
// Raw hex data, inserted NOT pushed onto stack:
|
||||
std::vector<unsigned char> raw = ParseHex(std::string(w.begin() + 2, w.end()));
|
||||
result.insert(result.end(), raw.begin(), raw.end());
|
||||
} else if (w.size() >= 2 && w.front() == '\'' && w.back() == '\'') {
|
||||
// Single-quoted string, pushed as data. NOTE: this is poor-man's
|
||||
// parsing, spaces/tabs/newlines in single-quoted strings won't work.
|
||||
std::vector<unsigned char> value(w.begin() + 1, w.end() - 1);
|
||||
result << value;
|
||||
} else {
|
||||
// opcode, e.g. OP_ADD or ADD:
|
||||
result << ParseOpCode(w);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Check that all of the input and output scripts of a transaction contain valid opcodes
|
||||
static bool CheckTxScriptsSanity(const CMutableTransaction& tx)
|
||||
{
|
||||
// Check input scripts for non-coinbase txs
|
||||
if (!CTransaction(tx).IsCoinBase()) {
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
if (!tx.vin[i].scriptSig.HasValidOps() || tx.vin[i].scriptSig.size() > MAX_SCRIPT_SIZE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check output scripts
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||
if (!tx.vout[i].scriptPubKey.HasValidOps() || tx.vout[i].scriptPubKey.size() > MAX_SCRIPT_SIZE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool DecodeTx(CMutableTransaction& tx, const std::vector<unsigned char>& tx_data, bool try_no_witness, bool try_witness)
|
||||
{
|
||||
// General strategy:
|
||||
// - Decode both with extended serialization (which interprets the 0x0001 tag as a marker for
|
||||
// the presence of witnesses) and with legacy serialization (which interprets the tag as a
|
||||
// 0-input 1-output incomplete transaction).
|
||||
// - Restricted by try_no_witness (which disables legacy if false) and try_witness (which
|
||||
// disables extended if false).
|
||||
// - Ignore serializations that do not fully consume the hex string.
|
||||
// - If neither succeeds, fail.
|
||||
// - If only one succeeds, return that one.
|
||||
// - If both decode attempts succeed:
|
||||
// - If only one passes the CheckTxScriptsSanity check, return that one.
|
||||
// - If neither or both pass CheckTxScriptsSanity, return the extended one.
|
||||
|
||||
CMutableTransaction tx_extended, tx_legacy;
|
||||
bool ok_extended = false, ok_legacy = false;
|
||||
|
||||
// Try decoding with extended serialization support, and remember if the result successfully
|
||||
// consumes the entire input.
|
||||
if (try_witness) {
|
||||
DataStream ssData(tx_data);
|
||||
try {
|
||||
ssData >> TX_WITH_WITNESS(tx_extended);
|
||||
if (ssData.empty()) ok_extended = true;
|
||||
} catch (const std::exception&) {
|
||||
// Fall through.
|
||||
}
|
||||
}
|
||||
|
||||
// Optimization: if extended decoding succeeded and the result passes CheckTxScriptsSanity,
|
||||
// don't bother decoding the other way.
|
||||
if (ok_extended && CheckTxScriptsSanity(tx_extended)) {
|
||||
tx = std::move(tx_extended);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try decoding with legacy serialization, and remember if the result successfully consumes the entire input.
|
||||
if (try_no_witness) {
|
||||
DataStream ssData(tx_data);
|
||||
try {
|
||||
ssData >> TX_NO_WITNESS(tx_legacy);
|
||||
if (ssData.empty()) ok_legacy = true;
|
||||
} catch (const std::exception&) {
|
||||
// Fall through.
|
||||
}
|
||||
}
|
||||
|
||||
// If legacy decoding succeeded and passes CheckTxScriptsSanity, that's our answer, as we know
|
||||
// at this point that extended decoding either failed or doesn't pass the sanity check.
|
||||
if (ok_legacy && CheckTxScriptsSanity(tx_legacy)) {
|
||||
tx = std::move(tx_legacy);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If extended decoding succeeded, and neither decoding passes sanity, return the extended one.
|
||||
if (ok_extended) {
|
||||
tx = std::move(tx_extended);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If legacy decoding succeeded and extended didn't, return the legacy one.
|
||||
if (ok_legacy) {
|
||||
tx = std::move(tx_legacy);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If none succeeded, we failed.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness, bool try_witness)
|
||||
{
|
||||
if (!IsHex(hex_tx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> txData(ParseHex(hex_tx));
|
||||
return DecodeTx(tx, txData, try_no_witness, try_witness);
|
||||
}
|
||||
|
||||
bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header)
|
||||
{
|
||||
if (!IsHex(hex_header)) return false;
|
||||
|
||||
const std::vector<unsigned char> header_data{ParseHex(hex_header)};
|
||||
DataStream ser_header{header_data};
|
||||
try {
|
||||
ser_header >> header;
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
|
||||
{
|
||||
if (!IsHex(strHexBlk))
|
||||
return false;
|
||||
|
||||
std::vector<unsigned char> blockData(ParseHex(strHexBlk));
|
||||
DataStream ssBlock(blockData);
|
||||
try {
|
||||
ssBlock >> TX_WITH_WITNESS(block);
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
util::Result<int> SighashFromStr(const std::string& sighash)
|
||||
{
|
||||
static const std::map<std::string, int> map_sighash_values = {
|
||||
{std::string("DEFAULT"), int(SIGHASH_DEFAULT)},
|
||||
{std::string("ALL"), int(SIGHASH_ALL)},
|
||||
{std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
|
||||
{std::string("NONE"), int(SIGHASH_NONE)},
|
||||
{std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},
|
||||
{std::string("SINGLE"), int(SIGHASH_SINGLE)},
|
||||
{std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},
|
||||
};
|
||||
const auto& it = map_sighash_values.find(sighash);
|
||||
if (it != map_sighash_values.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return util::Error{Untranslated("'" + sighash + "' is not a valid sighash parameter.")};
|
||||
}
|
||||
}
|
||||
|
||||
UniValue ValueFromAmount(const CAmount amount)
|
||||
{
|
||||
static_assert(COIN > 1);
|
||||
@@ -8,9 +8,8 @@
|
||||
#include <consensus/amount.h>
|
||||
#include <util/result.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
class CBlock;
|
||||
class CBlockHeader;
|
||||
@@ -32,7 +31,6 @@ enum class TxVerbosity {
|
||||
SHOW_DETAILS_AND_PREVOUT //!< The same as previous option with information about prevouts if available
|
||||
};
|
||||
|
||||
// core_read.cpp
|
||||
CScript ParseScript(const std::string& s);
|
||||
std::string ScriptToAsmStr(const CScript& script, bool fAttemptSighashDecode = false);
|
||||
[[nodiscard]] bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true);
|
||||
@@ -41,7 +39,6 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
|
||||
|
||||
[[nodiscard]] util::Result<int> SighashFromStr(const std::string& sighash);
|
||||
|
||||
// core_write.cpp
|
||||
UniValue ValueFromAmount(CAmount amount);
|
||||
std::string FormatScript(const CScript& script);
|
||||
std::string EncodeHexTx(const CTransaction& tx);
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
// Copyright (c) 2009-present The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <core_io.h>
|
||||
|
||||
#include <primitives/block.h> // IWYU pragma: keep
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/script.h>
|
||||
#include <serialize.h>
|
||||
#include <streams.h>
|
||||
#include <util/result.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/string.h>
|
||||
#include <util/translation.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using util::SplitString;
|
||||
|
||||
namespace {
|
||||
class OpCodeParser
|
||||
{
|
||||
private:
|
||||
std::map<std::string, opcodetype> mapOpNames;
|
||||
|
||||
public:
|
||||
OpCodeParser()
|
||||
{
|
||||
for (unsigned int op = 0; op <= MAX_OPCODE; ++op) {
|
||||
// Allow OP_RESERVED to get into mapOpNames
|
||||
if (op < OP_NOP && op != OP_RESERVED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string strName = GetOpName(static_cast<opcodetype>(op));
|
||||
if (strName == "OP_UNKNOWN") {
|
||||
continue;
|
||||
}
|
||||
mapOpNames[strName] = static_cast<opcodetype>(op);
|
||||
// Convenience: OP_ADD and just ADD are both recognized:
|
||||
if (strName.starts_with("OP_")) {
|
||||
mapOpNames[strName.substr(3)] = static_cast<opcodetype>(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
opcodetype Parse(const std::string& s) const
|
||||
{
|
||||
auto it = mapOpNames.find(s);
|
||||
if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode");
|
||||
return it->second;
|
||||
}
|
||||
};
|
||||
|
||||
opcodetype ParseOpCode(const std::string& s)
|
||||
{
|
||||
static const OpCodeParser ocp;
|
||||
return ocp.Parse(s);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CScript ParseScript(const std::string& s)
|
||||
{
|
||||
CScript result;
|
||||
|
||||
std::vector<std::string> words = SplitString(s, " \t\n");
|
||||
|
||||
for (const std::string& w : words) {
|
||||
if (w.empty()) {
|
||||
// Empty string, ignore. (SplitString doesn't combine multiple separators)
|
||||
} else if (std::all_of(w.begin(), w.end(), ::IsDigit) ||
|
||||
(w.front() == '-' && w.size() > 1 && std::all_of(w.begin() + 1, w.end(), ::IsDigit)))
|
||||
{
|
||||
// Number
|
||||
const auto num{ToIntegral<int64_t>(w)};
|
||||
|
||||
// limit the range of numbers ParseScript accepts in decimal
|
||||
// since numbers outside -0xFFFFFFFF...0xFFFFFFFF are illegal in scripts
|
||||
if (!num.has_value() || num > int64_t{0xffffffff} || num < -1 * int64_t{0xffffffff}) {
|
||||
throw std::runtime_error("script parse error: decimal numeric value only allowed in the "
|
||||
"range -0xFFFFFFFF...0xFFFFFFFF");
|
||||
}
|
||||
|
||||
result << num.value();
|
||||
} else if (w.starts_with("0x") && w.size() > 2 && IsHex(std::string(w.begin() + 2, w.end()))) {
|
||||
// Raw hex data, inserted NOT pushed onto stack:
|
||||
std::vector<unsigned char> raw = ParseHex(std::string(w.begin() + 2, w.end()));
|
||||
result.insert(result.end(), raw.begin(), raw.end());
|
||||
} else if (w.size() >= 2 && w.front() == '\'' && w.back() == '\'') {
|
||||
// Single-quoted string, pushed as data. NOTE: this is poor-man's
|
||||
// parsing, spaces/tabs/newlines in single-quoted strings won't work.
|
||||
std::vector<unsigned char> value(w.begin() + 1, w.end() - 1);
|
||||
result << value;
|
||||
} else {
|
||||
// opcode, e.g. OP_ADD or ADD:
|
||||
result << ParseOpCode(w);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check that all of the input and output scripts of a transaction contains valid opcodes
|
||||
static bool CheckTxScriptsSanity(const CMutableTransaction& tx)
|
||||
{
|
||||
// Check input scripts for non-coinbase txs
|
||||
if (!CTransaction(tx).IsCoinBase()) {
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
if (!tx.vin[i].scriptSig.HasValidOps() || tx.vin[i].scriptSig.size() > MAX_SCRIPT_SIZE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check output scripts
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||
if (!tx.vout[i].scriptPubKey.HasValidOps() || tx.vout[i].scriptPubKey.size() > MAX_SCRIPT_SIZE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool DecodeTx(CMutableTransaction& tx, const std::vector<unsigned char>& tx_data, bool try_no_witness, bool try_witness)
|
||||
{
|
||||
// General strategy:
|
||||
// - Decode both with extended serialization (which interprets the 0x0001 tag as a marker for
|
||||
// the presence of witnesses) and with legacy serialization (which interprets the tag as a
|
||||
// 0-input 1-output incomplete transaction).
|
||||
// - Restricted by try_no_witness (which disables legacy if false) and try_witness (which
|
||||
// disables extended if false).
|
||||
// - Ignore serializations that do not fully consume the hex string.
|
||||
// - If neither succeeds, fail.
|
||||
// - If only one succeeds, return that one.
|
||||
// - If both decode attempts succeed:
|
||||
// - If only one passes the CheckTxScriptsSanity check, return that one.
|
||||
// - If neither or both pass CheckTxScriptsSanity, return the extended one.
|
||||
|
||||
CMutableTransaction tx_extended, tx_legacy;
|
||||
bool ok_extended = false, ok_legacy = false;
|
||||
|
||||
// Try decoding with extended serialization support, and remember if the result successfully
|
||||
// consumes the entire input.
|
||||
if (try_witness) {
|
||||
DataStream ssData(tx_data);
|
||||
try {
|
||||
ssData >> TX_WITH_WITNESS(tx_extended);
|
||||
if (ssData.empty()) ok_extended = true;
|
||||
} catch (const std::exception&) {
|
||||
// Fall through.
|
||||
}
|
||||
}
|
||||
|
||||
// Optimization: if extended decoding succeeded and the result passes CheckTxScriptsSanity,
|
||||
// don't bother decoding the other way.
|
||||
if (ok_extended && CheckTxScriptsSanity(tx_extended)) {
|
||||
tx = std::move(tx_extended);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try decoding with legacy serialization, and remember if the result successfully consumes the entire input.
|
||||
if (try_no_witness) {
|
||||
DataStream ssData(tx_data);
|
||||
try {
|
||||
ssData >> TX_NO_WITNESS(tx_legacy);
|
||||
if (ssData.empty()) ok_legacy = true;
|
||||
} catch (const std::exception&) {
|
||||
// Fall through.
|
||||
}
|
||||
}
|
||||
|
||||
// If legacy decoding succeeded and passes CheckTxScriptsSanity, that's our answer, as we know
|
||||
// at this point that extended decoding either failed or doesn't pass the sanity check.
|
||||
if (ok_legacy && CheckTxScriptsSanity(tx_legacy)) {
|
||||
tx = std::move(tx_legacy);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If extended decoding succeeded, and neither decoding passes sanity, return the extended one.
|
||||
if (ok_extended) {
|
||||
tx = std::move(tx_extended);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If legacy decoding succeeded and extended didn't, return the legacy one.
|
||||
if (ok_legacy) {
|
||||
tx = std::move(tx_legacy);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If none succeeded, we failed.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness, bool try_witness)
|
||||
{
|
||||
if (!IsHex(hex_tx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> txData(ParseHex(hex_tx));
|
||||
return DecodeTx(tx, txData, try_no_witness, try_witness);
|
||||
}
|
||||
|
||||
bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header)
|
||||
{
|
||||
if (!IsHex(hex_header)) return false;
|
||||
|
||||
const std::vector<unsigned char> header_data{ParseHex(hex_header)};
|
||||
DataStream ser_header{header_data};
|
||||
try {
|
||||
ser_header >> header;
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
|
||||
{
|
||||
if (!IsHex(strHexBlk))
|
||||
return false;
|
||||
|
||||
std::vector<unsigned char> blockData(ParseHex(strHexBlk));
|
||||
DataStream ssBlock(blockData);
|
||||
try {
|
||||
ssBlock >> TX_WITH_WITNESS(block);
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
util::Result<int> SighashFromStr(const std::string& sighash)
|
||||
{
|
||||
static const std::map<std::string, int> map_sighash_values = {
|
||||
{std::string("DEFAULT"), int(SIGHASH_DEFAULT)},
|
||||
{std::string("ALL"), int(SIGHASH_ALL)},
|
||||
{std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
|
||||
{std::string("NONE"), int(SIGHASH_NONE)},
|
||||
{std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},
|
||||
{std::string("SINGLE"), int(SIGHASH_SINGLE)},
|
||||
{std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},
|
||||
};
|
||||
const auto& it = map_sighash_values.find(sighash);
|
||||
if (it != map_sighash_values.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return util::Error{Untranslated("'" + sighash + "' is not a valid sighash parameter.")};
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ add_library(bitcoinkernel
|
||||
../consensus/merkle.cpp
|
||||
../consensus/tx_check.cpp
|
||||
../consensus/tx_verify.cpp
|
||||
../core_read.cpp
|
||||
../dbwrapper.cpp
|
||||
../deploymentinfo.cpp
|
||||
../deploymentstatus.cpp
|
||||
@@ -72,8 +71,6 @@ add_library(bitcoinkernel
|
||||
../util/rbf.cpp
|
||||
../util/serfloat.cpp
|
||||
../util/signalinterrupt.cpp
|
||||
../util/strencodings.cpp
|
||||
../util/string.cpp
|
||||
../util/syserror.cpp
|
||||
../util/threadnames.cpp
|
||||
../util/time.cpp
|
||||
|
||||
Reference in New Issue
Block a user