Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

integrate taptree #264

Merged
merged 1 commit into from
Dec 3, 2023
Merged
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
2 changes: 1 addition & 1 deletion f469-disco
Submodule f469-disco updated 38 files
+1 −1 README.md
+1 −1 docs/readme.md
+1 −1 docs/tutorial/2_addresses_gui/readme.md
+1 −1 docs/tutorial/extra_blinky/blinky.ipynb
+33 −21 libs/common/embit/base.py
+8 −8 libs/common/embit/base58.py
+19 −12 libs/common/embit/bech32.py
+38 −39 libs/common/embit/bip32.py
+2 −7 libs/common/embit/bip39.py
+55 −0 libs/common/embit/bip85.py
+11 −6 libs/common/embit/compact.py
+101 −41 libs/common/embit/descriptor/arguments.py
+15 −31 libs/common/embit/descriptor/base.py
+14 −8 libs/common/embit/descriptor/checksum.py
+102 −42 libs/common/embit/descriptor/descriptor.py
+74 −24 libs/common/embit/descriptor/miniscript.py
+151 −0 libs/common/embit/descriptor/taptree.py
+31 −14 libs/common/embit/ec.py
+11 −7 libs/common/embit/hashes.py
+14 −8 libs/common/embit/liquid/addresses.py
+19 −15 libs/common/embit/liquid/blech32.py
+1 −0 libs/common/embit/liquid/blip32.py
+50 −11 libs/common/embit/liquid/descriptor.py
+54 −52 libs/common/embit/liquid/networks.py
+217 −126 libs/common/embit/liquid/pset.py
+57 −24 libs/common/embit/liquid/psetview.py
+6 −4 libs/common/embit/liquid/slip77.py
+122 −31 libs/common/embit/liquid/transaction.py
+70 −0 libs/common/embit/misc.py
+1 −6 libs/common/embit/networks.py
+282 −149 libs/common/embit/psbt.py
+326 −155 libs/common/embit/psbtview.py
+2 −8 libs/common/embit/script.py
+15 −46 libs/common/embit/slip39.py
+51 −18 libs/common/embit/transaction.py
+6 −2 libs/common/embit/wordlists/base.py
+1 −1 libs/common/embit/wordlists/bip39.py
+2 −2 usermods/udisplay_f469/lv_conf.h
5 changes: 3 additions & 2 deletions src/apps/wallets/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from .wallet import WalletError, Wallet
from .commands import DELETE, EDIT
from io import BytesIO
from bcur import bcur_decode_stream, bcur_encode_stream
from bcur import bcur_decode_stream
from helpers import a2b_base64_stream, b2a_base64_stream
import gc
import json
Expand Down Expand Up @@ -439,7 +439,7 @@ async def confirm_new_wallet(self, w, show_screen):
"None of the keys belong to the device.\n\n"
"Are you sure you still want to add the wallet?")):
return False
return await show_screen(ConfirmWalletScreen(w.name, w.full_policy, keys, w.is_miniscript))
return await show_screen(ConfirmWalletScreen(w.name, w.full_policy, keys, w.is_complex))

async def showaddr(
self, paths: list, script_type: str, redeem_script=None, show_screen=None
Expand Down Expand Up @@ -792,6 +792,7 @@ def sign_psbtview(self, psbtv, out_stream, wallets, sighash):
with open(self.tempdir+"/sigs", "rb") as sig_stream:
psbtv.write_to(out_stream, compress=CompressMode.PARTIAL, extra_input_streams=[sig_stream])


def wipe(self):
"""Deletes all wallets info"""
self.wallets = []
Expand Down
18 changes: 11 additions & 7 deletions src/apps/wallets/screens.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import lvgl as lv
from gui.common import add_label, add_button, HOR_RES, format_addr, PADDING
from gui.common import add_label, add_button, HOR_RES, format_addr
from gui.decorators import on_release
from gui.screens import QRAlert, Prompt, Alert
from .commands import DELETE, EDIT, MENU
Expand Down Expand Up @@ -123,10 +123,10 @@ def update_address(self):


class ConfirmWalletScreen(Prompt):
def __init__(self, name, policy, keys, is_miniscript=True):
def __init__(self, name, policy, keys, is_complex=True):
super().__init__('Add wallet "%s"?' % name, "")
self.policy = add_label("Policy: " + policy, y=75, scr=self)
self.is_miniscript = is_miniscript
self.is_complex = is_complex

lbl = lv.label(self)
lbl.set_text("Canonical xpub SLIP-132 ")
Expand All @@ -145,10 +145,12 @@ def fill_message(self):
msg = ""
arg = "slip132" if self.slip_switch.get_state() else "canonical"
for i, k in enumerate(self.keys):
alias = "" if not self.is_miniscript else " (%s)" % chr(65+i)
alias = "" if not self.is_complex else " (%s)" % chr(65+i)
kstr = str(k[arg]).replace("]","]\n")
if k["mine"]:
msg += "#7ED321 My key%s: #\n%s\n\n" % (alias, kstr)
elif k["is_nums"]:
msg += "#00CAF1 NUMS key%s: #\nNobody knows private key\n\n" % alias
elif k["is_private"]:
msg += "#F51E2D Private key%s: #\n%s\n\n" % (alias, kstr)
else:
Expand All @@ -157,10 +159,10 @@ def fill_message(self):

# TODO: refactor to remove duplication
class WalletInfoScreen(Alert):
def __init__(self, name, policy, keys, is_miniscript=True):
def __init__(self, name, policy, keys, is_complex=True):
super().__init__(name, "")
self.policy = add_label("Policy: " + policy, y=75, scr=self)
self.is_miniscript = is_miniscript
self.is_complex = is_complex

lbl = lv.label(self)
lbl.set_text("Canonical xpub SLIP-132 ")
Expand All @@ -179,10 +181,12 @@ def fill_message(self):
msg = ""
arg = "slip132" if self.slip_switch.get_state() else "canonical"
for i, k in enumerate(self.keys):
alias = "" if not self.is_miniscript else " (%s)" % chr(65+i)
alias = "" if not self.is_complex else " (%s)" % chr(65+i)
kstr = str(k[arg]).replace("]","]\n")
if k["mine"]:
msg += "#7ED321 My key%s: #\n%s\n\n" % (alias, kstr)
elif k["is_nums"]:
msg += "#AAAAAA NUMS key%s: #\nNobody knows private key\n\n" % alias
elif k["is_private"]:
msg += "#F51E2D Private key%s: #\n%s\n\n" % (alias, kstr)
else:
Expand Down
19 changes: 14 additions & 5 deletions src/apps/wallets/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
import platform
from platform import maybe_mkdir, delete_recursively
import json
from embit import ec, hashes, script
from embit import ec, hashes
from embit.networks import NETWORKS
from embit.psbt import DerivationPath
from embit.descriptor import Descriptor
from embit.descriptor.checksum import add_checksum
from embit.descriptor.arguments import AllowedDerivation
from embit.transaction import SIGHASH
import hashlib
from .screens import WalletScreen, WalletInfoScreen
from .commands import DELETE, EDIT, MENU, INFO, EXPORT
from gui.screens import Menu, QRAlert, Alert
Expand Down Expand Up @@ -57,7 +56,7 @@ async def show(self, network, show_screen):
keys = self.get_key_dicts(network)
for k in keys:
k["mine"] = True if self.keystore and self.keystore.owns(k["key"]) else False
await show_screen(WalletInfoScreen(self.name, self.full_policy, keys, self.is_miniscript))
await show_screen(WalletInfoScreen(self.name, self.full_policy, keys, self.is_complex))
continue
elif cmd == EXPORT:
await self.export_menu(show_screen)
Expand Down Expand Up @@ -252,6 +251,7 @@ def get_key_dicts(self, network):
k["slip132"] = k["key"].to_string(self.Networks[network][ver])
ver = canonical_ver.replace("pub", "prv") if k["is_private"] else canonical_ver
k["canonical"] = k["key"].to_string(self.Networks[network][ver])
k["is_nums"] = (k["key"].sec() == ec.NUMS_PUBKEY.sec()) # nothing up my sleeve
return keys

def sign_psbt(self, psbt, sighash=SIGHASH.ALL):
Expand Down Expand Up @@ -348,16 +348,25 @@ def full_policy(self):
else:
p = "Legacy\n"
pp = self.descriptor.full_policy
if not self.is_miniscript:
if not self.is_complex:
p += pp
else:
p += "Miniscript:\n"+pp.replace(",",", ")
prefix = "Miniscript:\n" if self.is_miniscript else "\n"
p += prefix+pp.replace(",",", ")
return p

@property
def is_miniscript(self):
return not (self.descriptor.is_basic_multisig or self.descriptor.is_pkh or self.descriptor.is_taproot)

@property
def is_taptree(self):
return bool(self.descriptor.taptree)

@property
def is_complex(self):
return self.is_miniscript or self.is_taptree

def __str__(self):
return "%s&%s" % (self.name, self.descriptor)

Expand Down
6 changes: 2 additions & 4 deletions test/integration/tests/test_with_rpc.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from unittest import TestCase, skip
from unittest import TestCase
from util.controller import sim
from util.rpc import prepare_rpc
import random
import time
from embit.descriptor import Descriptor
from embit.bip32 import HDKey
from embit.networks import NETWORKS
from embit.psbt import PSBT, DerivationPath
from embit.transaction import Transaction, TransactionInput, TransactionOutput, SIGHASH
from embit.transaction import Transaction, SIGHASH
from embit import ec, bip32
from embit.script import Witness

Expand Down
Empty file.
54 changes: 54 additions & 0 deletions test/integration/util/misc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from embit.descriptor import Descriptor
from embit.networks import NETWORKS
from .rpc import prepare_rpc

def create_wallet(wname, d1: str, d2: str, rpc=None):
if rpc is None:
rpc = prepare_rpc()
wdefault = rpc.wallet("")
# to derive addresses
desc1 = Descriptor.from_string(d1)

# recv addr
addr = desc1.derive(0).address(NETWORKS['regtest'])

# to add checksums
d1 = rpc.getdescriptorinfo(d1)["descriptor"]
d2 = rpc.getdescriptorinfo(d2)["descriptor"]
rpc.createwallet(wname, True, True)
w = rpc.wallet(wname)
info = w.getwalletinfo()
# bitcoin core uses descriptor wallets by default so importmulti may fail
use_descriptors = info.get("descriptors", False)
if not use_descriptors:
res = w.importmulti([{
"desc": d1,
"internal": False,
"timestamp": "now",
"watchonly": True,
"range": 10,
},{
"desc": d2,
"internal": True,
"timestamp": "now",
"watchonly": True,
"range": 10,
}],{"rescan": False})
else:
res = w.importdescriptors([{
"desc": d1,
"internal": False,
"timestamp": "now",
"watchonly": True,
"active": True,
},{
"desc": d2,
"internal": True,
"timestamp": "now",
"watchonly": True,
"active": True,
}])
assert all([k["success"] for k in res])
wdefault.sendtoaddress(addr, 0.1)
rpc.mine()
return w
2 changes: 1 addition & 1 deletion test/tests/test_compatibility.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from unittest import TestCase
from apps.compatibility import *
from apps.compatibility import parse_software_wallet_json, parse_cc_wallet_txt
import json
from io import BytesIO

Expand Down
2 changes: 1 addition & 1 deletion test/tests/test_keystore.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from unittest import TestCase
from keystore import FlashKeyStore
import os, json
import os
import platform

TEST_DIR = "testdir"
Expand Down
6 changes: 4 additions & 2 deletions test/tests/test_wallets.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from unittest import TestCase
from apps.wallets.wallet import Wallet
from embit.descriptor import Key
import os, json
import platform

TEST_DIR = "testdir"

Expand Down Expand Up @@ -60,3 +58,7 @@ def test_invalid_keys(self):
Key.parse(k)
print(k)

def test_taptree(self):
d = "tr([73c5da0a/2/2/2]tpubDCPwGho2toLmdSELZ3o8v1D6RUUK7Y5keCjMyrSfE75aX2Mcx4MNEM6MnXDZR87GQ1ot4YNn2GGtiN5SvM12c6cvYMrt6avwtYNcRab2HFv/<0;1>/*,or_b(pk([73c5da0a/1/2/3]tpubDCpEkdSHkygNaquCRtW8Fuo3TchAXFSWUuYB9aryim58T4CWM9vLgt26uUV5wdtuvbSk7rWmQQCpcYhGjbHiBzWCYXeyRMJ98zSBWekaJJm/<0;1>/*),s:pk([73c5da0a/3/2/1]tpubDDrLDbxjL1d5FK8djVqUjD3xL1gkhaTXTL1rHzEavwA2ss4YpF8Qm82cKN89PEBRYk6JVTZULA872LuFGENTGdNYASDCrXKKZkU86A8HLqA/<0;1>/*)))"
w = Wallet.parse(d)
print(w)
3 changes: 1 addition & 2 deletions test/tests/util.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from keystore.ram import RAMKeyStore
from app import BaseApp
from apps.wallets import App as WalletsApp
import os, json
import platform

TEST_DIR = "testdir"
Expand Down Expand Up @@ -48,4 +47,4 @@ def get_wallets_app(keystore, network):
BaseApp.tempdir = TEST_DIR+"/tmp"
wapp = WalletsApp(TEST_DIR+"/wallets")
wapp.init(keystore, network, show_loader, communicate)
return wapp
return wapp