Browse Source

Make more things miniscript::internal and move to cpp

analysis
Pieter Wuille 5 years ago
parent
commit
6dc1d84eca
  1. 59
      bitcoin/script/miniscript.cpp
  2. 98
      bitcoin/script/miniscript.h

59
bitcoin/script/miniscript.cpp

@ -136,6 +136,65 @@ Type CalcSimpleType(NodeType nodetype, Type x, Type y, Type z) {
return ""_mst; return ""_mst;
} }
InputStack& InputStack::WithSig() {
has_sig = true;
return *this;
}
InputStack& InputStack::NonCanon() {
non_canon = true;
return *this;
}
InputStack& InputStack::Malleable(bool x) {
malleable = x;
return *this;
}
bool operator<(const InputStack& a, const InputStack& b) {
return a.size < b.size;
}
InputStack operator+(InputStack a, InputStack b) {
if (!a.valid || !b.valid) {
a.valid = false;
a.stack.clear();
a.size = std::numeric_limits<size_t>::max();
a.has_sig = false;
a.malleable = false;
} else {
a.stack = Cat(std::move(a.stack), std::move(b.stack));
a.size += b.size;
a.has_sig |= b.has_sig;
a.malleable |= b.malleable;
a.non_canon |= b.non_canon;
}
return a;
}
InputStack Choose(InputStack a, InputStack b, bool nonmalleable) {
// If only one (or neither) is valid, pick the other one.
if (!a.valid) return b;
if (!b.valid) return a;
// If both are valid, they must be distinct.
assert(a.stack != b.stack);
if (nonmalleable) {
// If both options are weak, any result is fine; it just needs the malleable marker.
if (!a.has_sig && !b.has_sig) return a.Malleable();
// If one option is weak, we must pick that one.
if (!a.has_sig) return a;
if (!b.has_sig) return b;
// If both options are strong, prefer the canonical one.
if (b.non_canon) return a;
if (a.non_canon) return b;
// If both options are strong and canonical, prefer the nonmalleable one.
if (b.malleable) return a;
if (a.malleable) return b;
}
// Otherwise just pick the smallest one.
return std::min(a, b);
}
bool DecomposeScript(const CScript& script, std::vector<std::pair<opcodetype, std::vector<unsigned char>>>& out) bool DecomposeScript(const CScript& script, std::vector<std::pair<opcodetype, std::vector<unsigned char>>>& out)
{ {
out.clear(); out.clear();

98
bitcoin/script/miniscript.h

@ -198,9 +198,6 @@ Type CalcSimpleType(NodeType nodetype, Type x, Type y, Type z);
//! A helper sanitizer/checker for the output of CalcType. //! A helper sanitizer/checker for the output of CalcType.
Type SanitizeType(Type x); Type SanitizeType(Type x);
} // namespace internal
struct InputStack { struct InputStack {
bool valid = false; bool valid = false;
bool has_sig = false; bool has_sig = false;
@ -217,62 +214,22 @@ struct InputStack {
explicit InputStack(bool val) : valid(val), size(valid ? 0 : std::numeric_limits<size_t>::max()) {} explicit InputStack(bool val) : valid(val), size(valid ? 0 : std::numeric_limits<size_t>::max()) {}
InputStack(std::vector<unsigned char> in) : valid(true), size(in.size() + 1), stack(Vector(std::move(in))) {} InputStack(std::vector<unsigned char> in) : valid(true), size(in.size() + 1), stack(Vector(std::move(in))) {}
InputStack& WithSig() { //! Mark this input stack as having a signature.
has_sig = true; InputStack& WithSig();
return *this;
}
InputStack& NonCanon() { //! Mark this input stack as non-canonical (known to not be necessary in non-malleable satisfactions).
non_canon = true; InputStack& NonCanon();
return *this;
}
InputStack& Malleable(bool x = true) { //! Mark this input stack as malleable.
malleable = x; InputStack& Malleable(bool x = true);
return *this;
}
bool operator<(const InputStack& b) const { return size < b.size; } friend bool operator<(const InputStack& a, const InputStack& b);
friend InputStack operator+(InputStack a, InputStack b) { //! Concatenate two input stacks.
if (!a.valid || !b.valid) { friend InputStack operator+(InputStack a, InputStack b);
a.valid = false;
a.stack.clear();
a.size = std::numeric_limits<size_t>::max();
a.has_sig = false;
a.malleable = false;
} else {
a.stack = Cat(std::move(a.stack), std::move(b.stack));
a.size += b.size;
a.has_sig |= b.has_sig;
a.malleable |= b.malleable;
a.non_canon |= b.non_canon;
}
return a;
}
friend inline InputStack Choose(InputStack a, InputStack b, bool nonmalleable) { //! Choose between two potential input stacks.
// If only one (or neither) is valid, pick the other one. friend InputStack Choose(InputStack a, InputStack b, bool nonmalleable);
if (!a.valid) return b;
if (!b.valid) return a;
// If both are valid, they must be distinct.
assert(a.stack != b.stack);
if (nonmalleable) {
// If both options are weak, any result is fine; it just needs the malleable marker.
if (!a.has_sig && !b.has_sig) return a.Malleable();
// If one option is weak, we must pick that one.
if (!a.has_sig) return a;
if (!b.has_sig) return b;
// If both options are strong, prefer the canonical one.
if (b.non_canon) return a;
if (a.non_canon) return b;
// If both options are strong and canonical, prefer the nonmalleable one.
if (b.malleable) return a;
if (a.malleable) return b;
}
// Otherwise just pick the smallest one.
return std::min(a, b);
}
}; };
struct InputResult { struct InputResult {
@ -281,6 +238,8 @@ struct InputResult {
InputResult(InputStack in_nsat, InputStack in_sat) : nsat(std::move(in_nsat)), sat(std::move(in_sat)) {} InputResult(InputStack in_nsat, InputStack in_sat) : nsat(std::move(in_nsat)), sat(std::move(in_sat)) {}
}; };
} // namespace internal
//! A node in a miniscript expression. //! A node in a miniscript expression.
template<typename Key> template<typename Key>
struct Node { struct Node {
@ -299,7 +258,6 @@ struct Node {
//! Subexpressions (for WRAP_*/AND_*/OR_*/ANDOR/THRESH) //! Subexpressions (for WRAP_*/AND_*/OR_*/ANDOR/THRESH)
const std::vector<NodeRef<Key>> subs; const std::vector<NodeRef<Key>> subs;
private: private:
//! Non-push opcodes in the corresponding script (static, non-sat, sat) //! Non-push opcodes in the corresponding script (static, non-sat, sat)
const int ops, nops, sops; const int ops, nops, sops;
@ -350,6 +308,8 @@ private:
//! Compute the type for this miniscript. //! Compute the type for this miniscript.
Type CalcType() const { Type CalcType() const {
using namespace internal;
// Sanity check on sigops // Sanity check on sigops
if (GetOps() > 201) return ""_mst; if (GetOps() > 201) return ""_mst;
@ -420,7 +380,7 @@ private:
Type x = subs.size() > 0 ? subs[0]->GetType() : ""_mst; Type x = subs.size() > 0 ? subs[0]->GetType() : ""_mst;
Type y = subs.size() > 1 ? subs[1]->GetType() : ""_mst; Type y = subs.size() > 1 ? subs[1]->GetType() : ""_mst;
Type z = subs.size() > 2 ? subs[2]->GetType() : ""_mst; Type z = subs.size() > 2 ? subs[2]->GetType() : ""_mst;
return internal::SanitizeType(internal::CalcSimpleType(nodetype, x, y, z)); return SanitizeType(CalcSimpleType(nodetype, x, y, z));
} }
//! Internal code for ToScript. //! Internal code for ToScript.
@ -626,7 +586,7 @@ private:
} }
template<typename Ctx> template<typename Ctx>
InputResult ProduceInput(const Ctx& ctx, bool nonmal) const { internal::InputResult ProduceInput(const Ctx& ctx, bool nonmal) const {
auto ret = ProduceInputHelper(ctx, nonmal); auto ret = ProduceInputHelper(ctx, nonmal);
// Do a consistency check between the satisfaction code and the type checker // Do a consistency check between the satisfaction code and the type checker
// (the actual satisfaction code in ProduceInputHelper does not use GetType) // (the actual satisfaction code in ProduceInputHelper does not use GetType)
@ -649,13 +609,15 @@ private:
} }
template<typename Ctx> template<typename Ctx>
InputResult ProduceInputHelper(const Ctx& ctx, bool nonmal) const { internal::InputResult ProduceInputHelper(const Ctx& ctx, bool nonmal) const {
static const InputStack ZERO = InputStack(std::vector<unsigned char>()); using namespace internal;
static const InputStack ZERO32 = InputStack(std::vector<unsigned char>(32, 0)).Malleable();
static const InputStack ONE = InputStack(Vector((unsigned char)1)); const auto ZERO = InputStack(std::vector<unsigned char>());
static const InputStack EMPTY = InputStack(true); const auto ZERO32 = InputStack(std::vector<unsigned char>(32, 0)).Malleable();
static const InputStack MALLEABLE_EMPTY = InputStack(true).Malleable(); const auto ONE = InputStack(Vector((unsigned char)1));
static const InputStack INVALID = InputStack(false); const auto EMPTY = InputStack(true);
const auto MALLEABLE_EMPTY = InputStack(true).Malleable();
const auto INVALID = InputStack(false);
switch (nodetype) { switch (nodetype) {
case NodeType::PK: { case NodeType::PK: {
@ -1253,8 +1215,9 @@ inline NodeRef<Key> DecodeWrapped(I& in, I last, const Ctx& ctx) {
template<typename Ctx> template<typename Ctx>
inline NodeRef<typename Ctx::Key> FromString(const std::string& str, const Ctx& ctx) { inline NodeRef<typename Ctx::Key> FromString(const std::string& str, const Ctx& ctx) {
using namespace internal;
Span<const char> span = MakeSpan(str); Span<const char> span = MakeSpan(str);
auto ret = internal::Parse<typename Ctx::Key>(span, ctx); auto ret = Parse<typename Ctx::Key>(span, ctx);
if (!ret || span.size()) return {}; if (!ret || span.size()) return {};
// if (!(ret->GetType() << "B"_mst)) return {}; // if (!(ret->GetType() << "B"_mst)) return {};
return ret; return ret;
@ -1262,10 +1225,11 @@ inline NodeRef<typename Ctx::Key> FromString(const std::string& str, const Ctx&
template<typename Ctx> template<typename Ctx>
inline NodeRef<typename Ctx::Key> FromScript(const CScript& script, const Ctx& ctx) { inline NodeRef<typename Ctx::Key> FromScript(const CScript& script, const Ctx& ctx) {
using namespace internal;
std::vector<std::pair<opcodetype, std::vector<unsigned char>>> decomposed; std::vector<std::pair<opcodetype, std::vector<unsigned char>>> decomposed;
if (!internal::DecomposeScript(script, decomposed)) return {}; if (!DecomposeScript(script, decomposed)) return {};
auto it = decomposed.begin(); auto it = decomposed.begin();
auto ret = internal::DecodeMulti<typename Ctx::Key>(it, decomposed.end(), ctx); auto ret = DecodeMulti<typename Ctx::Key>(it, decomposed.end(), ctx);
if (!ret) return {}; if (!ret) return {};
if (!(ret->GetType() << "B"_mst)) return {}; if (!(ret->GetType() << "B"_mst)) return {};
if (it != decomposed.end()) return {}; if (it != decomposed.end()) return {};

Loading…
Cancel
Save