Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions bitcoin/script/miniscript.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <span.h>
#include <util/spanparsing.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/vector.h>
#include <primitives/transaction.h>

Expand Down Expand Up @@ -612,8 +613,8 @@ struct Node {
if (!ctx.ToString(node.keys[0], key_str)) return {};
return std::move(ret) + "pk_h(" + std::move(key_str) + ")";
}
case NodeType::AFTER: return std::move(ret) + "after(" + std::to_string(node.k) + ")";
case NodeType::OLDER: return std::move(ret) + "older(" + std::to_string(node.k) + ")";
case NodeType::AFTER: return std::move(ret) + "after(" + ::ToString(node.k) + ")";
case NodeType::OLDER: return std::move(ret) + "older(" + ::ToString(node.k) + ")";
case NodeType::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
case NodeType::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
case NodeType::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
Expand All @@ -631,7 +632,7 @@ struct Node {
if (node.subs[2]->nodetype == NodeType::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
case NodeType::MULTI: {
auto str = std::move(ret) + "multi(" + std::to_string(node.k);
auto str = std::move(ret) + "multi(" + ::ToString(node.k);
for (const auto& key : node.keys) {
std::string key_str;
if (!ctx.ToString(key, key_str)) return {};
Expand All @@ -640,7 +641,7 @@ struct Node {
return std::move(str) + ")";
}
case NodeType::THRESH: {
auto str = std::move(ret) + "thresh(" + std::to_string(node.k);
auto str = std::move(ret) + "thresh(" + ::ToString(node.k);
for (auto& sub : subs) {
str += "," + std::move(sub);
}
Expand Down
5 changes: 2 additions & 3 deletions bitcoin/test/miniscript_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,12 +503,11 @@ void Test(const std::string& ms, const std::string& hexscript, int mode, int ops
auto inferred_miniscript = miniscript::FromScript(computed_script, CONVERTER);
BOOST_CHECK_MESSAGE(inferred_miniscript, "Cannot infer miniscript from script: " + ms);
BOOST_CHECK_MESSAGE(inferred_miniscript->ToScript(CONVERTER) == computed_script, "Roundtrip failure: miniscript->script != miniscript->script->miniscript->script: " + ms);
if (opslimit != -1) BOOST_CHECK_MESSAGE((int)node->GetOps() == opslimit, "Ops limit mismatch: " + ms + " (" + std::to_string(node->GetOps()) + " vs " + std::to_string(opslimit) + ")");
if (stacklimit != -1) BOOST_CHECK_MESSAGE((int)node->GetStackSize() == stacklimit, "Stack limit mismatch: " + ms + " (" + std::to_string(node->GetStackSize()) + " vs " + std::to_string(stacklimit) + ")");
if (opslimit != -1) BOOST_CHECK_MESSAGE((int)node->GetOps() == opslimit, "Ops limit mismatch: " << ms << " (" << node->GetOps() << " vs " << opslimit << ")");
if (stacklimit != -1) BOOST_CHECK_MESSAGE((int)node->GetStackSize() == stacklimit, "Stack limit mismatch: " << ms << " (" << node->GetStackSize() << " vs " << stacklimit << ")");
TestSatisfy(ms, node);
}
}

} // namespace

BOOST_FIXTURE_TEST_SUITE(miniscript_tests, BasicTestingSetup)
Expand Down
106 changes: 106 additions & 0 deletions bitcoin/util/string.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) 2019-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_UTIL_STRING_H
#define BITCOIN_UTIL_STRING_H

#include <attributes.h>

#include <algorithm>
#include <array>
#include <cstring>
#include <locale>
#include <sstream>
#include <string>
#include <vector>

[[nodiscard]] inline std::string TrimString(const std::string& str, const std::string& pattern = " \f\n\r\t\v")
{
std::string::size_type front = str.find_first_not_of(pattern);
if (front == std::string::npos) {
return std::string();
}
std::string::size_type end = str.find_last_not_of(pattern);
return str.substr(front, end - front + 1);
}

[[nodiscard]] inline std::string RemovePrefix(const std::string& str, const std::string& prefix)
{
if (str.substr(0, prefix.size()) == prefix) {
return str.substr(prefix.size());
}
return str;
}

/**
* Join a list of items
*
* @param list The list to join
* @param separator The separator
* @param unary_op Apply this operator to each item in the list
*/
template <typename T, typename BaseType, typename UnaryOp>
auto Join(const std::vector<T>& list, const BaseType& separator, UnaryOp unary_op)
-> decltype(unary_op(list.at(0)))
{
decltype(unary_op(list.at(0))) ret;
for (size_t i = 0; i < list.size(); ++i) {
if (i > 0) ret += separator;
ret += unary_op(list.at(i));
}
return ret;
}

template <typename T>
T Join(const std::vector<T>& list, const T& separator)
{
return Join(list, separator, [](const T& i) { return i; });
}

// Explicit overload needed for c_str arguments, which would otherwise cause a substitution failure in the template above.
inline std::string Join(const std::vector<std::string>& list, const std::string& separator)
{
return Join<std::string>(list, separator);
}

/**
* Create an unordered multi-line list of items.
*/
inline std::string MakeUnorderedList(const std::vector<std::string>& items)
{
return Join(items, "\n", [](const std::string& item) { return "- " + item; });
}

/**
* Check if a string does not contain any embedded NUL (\0) characters
*/
[[nodiscard]] inline bool ValidAsCString(const std::string& str) noexcept
{
return str.size() == strlen(str.c_str());
}

/**
* Locale-independent version of std::to_string
*/
template <typename T>
std::string ToString(const T& t)
{
std::ostringstream oss;
oss.imbue(std::locale::classic());
oss << t;
return oss.str();
}

/**
* Check whether a container begins with the given prefix.
*/
template <typename T1, size_t PREFIX_LEN>
[[nodiscard]] inline bool HasPrefix(const T1& obj,
const std::array<uint8_t, PREFIX_LEN>& prefix)
{
return obj.size() >= PREFIX_LEN &&
std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
}

#endif // BITCOIN_UTIL_STRING_H