mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-22 23:07:59 +01:00
Abstract out some of the descriptor Span-parsing helpers
This commit is contained in:
parent
796b713633
commit
230d43fdbc
4 changed files with 107 additions and 57 deletions
|
@ -208,6 +208,7 @@ BITCOIN_CORE_H = \
|
||||||
util/bytevectorhash.h \
|
util/bytevectorhash.h \
|
||||||
util/error.h \
|
util/error.h \
|
||||||
util/fees.h \
|
util/fees.h \
|
||||||
|
util/spanparsing.h \
|
||||||
util/system.h \
|
util/system.h \
|
||||||
util/memory.h \
|
util/memory.h \
|
||||||
util/moneystr.h \
|
util/moneystr.h \
|
||||||
|
@ -503,6 +504,7 @@ libbitcoin_util_a_SOURCES = \
|
||||||
util/moneystr.cpp \
|
util/moneystr.cpp \
|
||||||
util/rbf.cpp \
|
util/rbf.cpp \
|
||||||
util/threadnames.cpp \
|
util/threadnames.cpp \
|
||||||
|
util/spanparsing.cpp \
|
||||||
util/strencodings.cpp \
|
util/strencodings.cpp \
|
||||||
util/string.cpp \
|
util/string.cpp \
|
||||||
util/time.cpp \
|
util/time.cpp \
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <span.h>
|
#include <span.h>
|
||||||
#include <util/bip32.h>
|
#include <util/bip32.h>
|
||||||
|
#include <util/spanparsing.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
|
|
||||||
|
@ -632,63 +633,6 @@ enum class ParseScriptContext {
|
||||||
P2WSH,
|
P2WSH,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Parse a constant. If successful, sp is updated to skip the constant and return true. */
|
|
||||||
bool Const(const std::string& str, Span<const char>& sp)
|
|
||||||
{
|
|
||||||
if ((size_t)sp.size() >= str.size() && std::equal(str.begin(), str.end(), sp.begin())) {
|
|
||||||
sp = sp.subspan(str.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parse a function call. If successful, sp is updated to be the function's argument(s). */
|
|
||||||
bool Func(const std::string& str, Span<const char>& sp)
|
|
||||||
{
|
|
||||||
if ((size_t)sp.size() >= str.size() + 2 && sp[str.size()] == '(' && sp[sp.size() - 1] == ')' && std::equal(str.begin(), str.end(), sp.begin())) {
|
|
||||||
sp = sp.subspan(str.size() + 1, sp.size() - str.size() - 2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return the expression that sp begins with, and update sp to skip it. */
|
|
||||||
Span<const char> Expr(Span<const char>& sp)
|
|
||||||
{
|
|
||||||
int level = 0;
|
|
||||||
auto it = sp.begin();
|
|
||||||
while (it != sp.end()) {
|
|
||||||
if (*it == '(') {
|
|
||||||
++level;
|
|
||||||
} else if (level && *it == ')') {
|
|
||||||
--level;
|
|
||||||
} else if (level == 0 && (*it == ')' || *it == ',')) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
Span<const char> ret = sp.first(it - sp.begin());
|
|
||||||
sp = sp.subspan(it - sp.begin());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Split a string on every instance of sep, returning a vector. */
|
|
||||||
std::vector<Span<const char>> Split(const Span<const char>& sp, char sep)
|
|
||||||
{
|
|
||||||
std::vector<Span<const char>> ret;
|
|
||||||
auto it = sp.begin();
|
|
||||||
auto start = it;
|
|
||||||
while (it != sp.end()) {
|
|
||||||
if (*it == sep) {
|
|
||||||
ret.emplace_back(start, it);
|
|
||||||
start = it + 1;
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
ret.emplace_back(start, it);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parse a key path, being passed a split list of elements (the first element is ignored). */
|
/** Parse a key path, being passed a split list of elements (the first element is ignored). */
|
||||||
NODISCARD bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, std::string& error)
|
NODISCARD bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, std::string& error)
|
||||||
{
|
{
|
||||||
|
@ -715,6 +659,8 @@ NODISCARD bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath&
|
||||||
/** Parse a public key that excludes origin information. */
|
/** Parse a public key that excludes origin information. */
|
||||||
std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
|
std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
|
||||||
{
|
{
|
||||||
|
using namespace spanparsing;
|
||||||
|
|
||||||
auto split = Split(sp, '/');
|
auto split = Split(sp, '/');
|
||||||
std::string str(split[0].begin(), split[0].end());
|
std::string str(split[0].begin(), split[0].end());
|
||||||
if (str.size() == 0) {
|
if (str.size() == 0) {
|
||||||
|
@ -774,6 +720,8 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char>& sp, boo
|
||||||
/** Parse a public key including origin information (if enabled). */
|
/** Parse a public key including origin information (if enabled). */
|
||||||
std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
|
std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
|
||||||
{
|
{
|
||||||
|
using namespace spanparsing;
|
||||||
|
|
||||||
auto origin_split = Split(sp, ']');
|
auto origin_split = Split(sp, ']');
|
||||||
if (origin_split.size() > 2) {
|
if (origin_split.size() > 2) {
|
||||||
error = "Multiple ']' characters found for a single pubkey";
|
error = "Multiple ']' characters found for a single pubkey";
|
||||||
|
@ -808,6 +756,8 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool per
|
||||||
/** Parse a script in a particular context. */
|
/** Parse a script in a particular context. */
|
||||||
std::unique_ptr<DescriptorImpl> ParseScript(Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
|
std::unique_ptr<DescriptorImpl> ParseScript(Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
|
||||||
{
|
{
|
||||||
|
using namespace spanparsing;
|
||||||
|
|
||||||
auto expr = Expr(sp);
|
auto expr = Expr(sp);
|
||||||
if (Func("pk", expr)) {
|
if (Func("pk", expr)) {
|
||||||
auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out, error);
|
auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out, error);
|
||||||
|
@ -1003,6 +953,8 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
|
||||||
/** Check a descriptor checksum, and update desc to be the checksum-less part. */
|
/** Check a descriptor checksum, and update desc to be the checksum-less part. */
|
||||||
bool CheckChecksum(Span<const char>& sp, bool require_checksum, std::string& error, std::string* out_checksum = nullptr)
|
bool CheckChecksum(Span<const char>& sp, bool require_checksum, std::string& error, std::string* out_checksum = nullptr)
|
||||||
{
|
{
|
||||||
|
using namespace spanparsing;
|
||||||
|
|
||||||
auto check_split = Split(sp, '#');
|
auto check_split = Split(sp, '#');
|
||||||
if (check_split.size() > 2) {
|
if (check_split.size() > 2) {
|
||||||
error = "Multiple '#' symbols";
|
error = "Multiple '#' symbols";
|
||||||
|
|
67
src/util/spanparsing.cpp
Normal file
67
src/util/spanparsing.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright (c) 2018 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 <util/spanparsing.h>
|
||||||
|
|
||||||
|
#include <span.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace spanparsing {
|
||||||
|
|
||||||
|
bool Const(const std::string& str, Span<const char>& sp)
|
||||||
|
{
|
||||||
|
if ((size_t)sp.size() >= str.size() && std::equal(str.begin(), str.end(), sp.begin())) {
|
||||||
|
sp = sp.subspan(str.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Func(const std::string& str, Span<const char>& sp)
|
||||||
|
{
|
||||||
|
if ((size_t)sp.size() >= str.size() + 2 && sp[str.size()] == '(' && sp[sp.size() - 1] == ')' && std::equal(str.begin(), str.end(), sp.begin())) {
|
||||||
|
sp = sp.subspan(str.size() + 1, sp.size() - str.size() - 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<const char> Expr(Span<const char>& sp)
|
||||||
|
{
|
||||||
|
int level = 0;
|
||||||
|
auto it = sp.begin();
|
||||||
|
while (it != sp.end()) {
|
||||||
|
if (*it == '(') {
|
||||||
|
++level;
|
||||||
|
} else if (level && *it == ')') {
|
||||||
|
--level;
|
||||||
|
} else if (level == 0 && (*it == ')' || *it == ',')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
Span<const char> ret = sp.first(it - sp.begin());
|
||||||
|
sp = sp.subspan(it - sp.begin());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Span<const char>> Split(const Span<const char>& sp, char sep)
|
||||||
|
{
|
||||||
|
std::vector<Span<const char>> ret;
|
||||||
|
auto it = sp.begin();
|
||||||
|
auto start = it;
|
||||||
|
while (it != sp.end()) {
|
||||||
|
if (*it == sep) {
|
||||||
|
ret.emplace_back(start, it);
|
||||||
|
start = it + 1;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
ret.emplace_back(start, it);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace spanparsing
|
29
src/util/spanparsing.h
Normal file
29
src/util/spanparsing.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright (c) 2018 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_SPANPARSING_H
|
||||||
|
#define BITCOIN_UTIL_SPANPARSING_H
|
||||||
|
|
||||||
|
#include <span.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace spanparsing {
|
||||||
|
|
||||||
|
/** Parse a constant. If successful, sp is updated to skip the constant and return true. */
|
||||||
|
bool Const(const std::string& str, Span<const char>& sp);
|
||||||
|
|
||||||
|
/** Parse a function call. If successful, sp is updated to be the function's argument(s). */
|
||||||
|
bool Func(const std::string& str, Span<const char>& sp);
|
||||||
|
|
||||||
|
/** Return the expression that sp begins with, and update sp to skip it. */
|
||||||
|
Span<const char> Expr(Span<const char>& sp);
|
||||||
|
|
||||||
|
/** Split a string on every instance of sep, returning a vector. */
|
||||||
|
std::vector<Span<const char>> Split(const Span<const char>& sp, char sep);
|
||||||
|
|
||||||
|
} // namespace spanparsing
|
||||||
|
|
||||||
|
#endif // BITCOIN_UTIL_SPANPARSING_H
|
Loading…
Add table
Reference in a new issue