mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-31 02:31:07 +00:00
refactor: [move-only] Merge core_io module
This can be reviewed with the git option --color-moved=dimmed-zebra
This commit is contained in:
parent
fa6947f491
commit
faf66673ac
@ -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 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.")};
|
||||
}
|
||||
}
|
||||
|
||||
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.")};
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user