Skip to content
Open
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
45 changes: 38 additions & 7 deletions src/embit/descriptor/miniscript.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,25 @@ def type(self):

@classmethod
def read_from(cls, s, taproot=False):
op, char = read_until(s, b"(")
def wrapped(m_script):
for w in reversed(wrappers):
if w not in WRAPPER_NAMES:
raise MiniscriptError("Unknown wrapper")
WrapperCls = WRAPPERS[WRAPPER_NAMES.index(w)]
m_script = WrapperCls(m_script, taproot=taproot)
return m_script

op, char = read_until(s, b"(,)")
if char in (b",", b")"):
s.seek(-1, 1)
op = op.decode()
wrappers = ""
if ":" in op:
wrappers, op = op.split(":")
# handle boolean literals: 0 or 1
if op in ("0", "1"):
miniscript = JustOne() if op == "1" else JustZero()
return wrapped(miniscript)
if char != b"(":
raise MiniscriptError("Missing operator")
if op not in OPERATOR_NAMES:
Expand All @@ -67,12 +81,7 @@ def read_from(cls, s, taproot=False):
MiniscriptCls = OPERATORS[OPERATOR_NAMES.index(op)]
args = MiniscriptCls.read_arguments(s, taproot=taproot)
miniscript = MiniscriptCls(*args, taproot=taproot)
for w in reversed(wrappers):
if w not in WRAPPER_NAMES:
raise MiniscriptError("Unknown wrapper")
WrapperCls = WRAPPERS[WRAPPER_NAMES.index(w)]
miniscript = WrapperCls(miniscript, taproot=taproot)
return miniscript
return wrapped(miniscript)

@classmethod
def read_arguments(cls, s, taproot=False):
Expand Down Expand Up @@ -119,6 +128,28 @@ def len_args(self):
########### Known fragments (miniscript operators) ##############


class JustZero(Miniscript):
TYPE = "B"
PROPS = "zud"

def inner_compile(self):
return Number(0).compile()

def __str__(self):
return "0"


class JustOne(Miniscript):
TYPE = "B"
PROPS = "zu"

def inner_compile(self):
return Number(1).compile()

def __str__(self):
return "1"


class OneArg(Miniscript):
NARGS = 1

Expand Down
6 changes: 5 additions & 1 deletion tests/tests/test_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from embit.descriptor.miniscript import OPERATORS, WRAPPERS
from embit.descriptor.errors import MiniscriptError
from embit.descriptor.checksum import add_checksum, DescriptorError
from embit.networks import NETWORKS
from embit import ec


Expand Down Expand Up @@ -194,10 +195,13 @@ def test_miniscript_compat(self):
"wsh(andor(thresh(1,pk(xpub6BaZSKgpaVvibu2k78QsqeDWXp92xLHZxiu1WoqLB9hKhsBf3miBUDX7PJLgSPvkj66ThVHTqdnbXpeu8crXFmDUd4HeM4s4miQS2xsv3Qb/*)),and_v(v:multi(2,03b506a1dbe57b4bf48c95e0c7d417b87dd3b4349d290d2e7e9ba72c912652d80a,0295e7f5d12a2061f1fd2286cefec592dff656a19f55f4f01305d6aa56630880ce),older(6)),thresh(2,pkh(xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU/*),a:pkh(xpub6AaffFGfH6WXfm6pwWzmUMuECQnoLeB3agMKaLyEBZ5ZVfwtnS5VJKqXBt8o5ooCWVy2H87GsZshp7DeKE25eWLyd1Ccuh2ZubQUkgpiVux/*))))#76jsyzdg",
"wsh(or_d(pk([40259ab7/48'/1'/0'/2']tpubDFcY6nTiMAWBd5d2bS8JZvjcaLjC6GE6XnPAJAPUkVj5wa5Pyb4gumx1ZWvnXQ8tmorCmpAyai69K9hD2mGQUeNkuXfjztsfqnE5FMk1CCh/<0;1>/*),and_v(v:pkh([842a626e/48'/1'/0'/2']tpubDENBboujRvpkS8SgZsrpqG2BCUBoaAc4c57jHFe1NwKAtfVjDZDUadQKYv4pkAEF2afPv6TtQ2BoYFJAPLbuKpL1usiySERZekGo4JmnWhh/<0;1>/*),older(65535))))#deguz53x",
"wsh(or_d(pk([40259ab7/48h/1h/0h/2h]tpubDFcY6nTiMAWBd5d2bS8JZvjcaLjC6GE6XnPAJAPUkVj5wa5Pyb4gumx1ZWvnXQ8tmorCmpAyai69K9hD2mGQUeNkuXfjztsfqnE5FMk1CCh/<0;1>/*),and_v(v:pkh([842a626e/48H/1H/0H/2H]tpubDENBboujRvpkS8SgZsrpqG2BCUBoaAc4c57jHFe1NwKAtfVjDZDUadQKYv4pkAEF2afPv6TtQ2BoYFJAPLbuKpL1usiySERZekGo4JmnWhh/<0;1>/*),older(65535))))#deguz53x",
"wsh(and_v(v:0,and_v(v:pk([40259ab7/48h/1h/0h/2h]tpubDFcY6nTiMAWBd5d2bS8JZvjcaLjC6GE6XnPAJAPUkVj5wa5Pyb4gumx1ZWvnXQ8tmorCmpAyai69K9hD2mGQUeNkuXfjztsfqnE5FMk1CCh/<0;1>/*),pk([40259ab7/48h/1h/0h/2h]tpubDFcY6nTiMAWBd5d2bS8JZvjcaLjC6GE6XnPAJAPUkVj5wa5Pyb4gumx1ZWvnXQ8tmorCmpAyai69K9hD2mGQUeNkuXfjztsfqnE5FMk1CCh/<0;1>/*))))",
"wsh(and_v(v:0,and_v(v:0,0)))",
]

for desc in generalistic_descs:
Descriptor.from_string(desc)
desc = Descriptor.from_string(desc)
desc.derive(0, 0).address(network=NETWORKS["main"])

def test_len(self):
"""Checks that len(miniscript) returns correct length"""
Expand Down