Skip to content

Commit 3a8395c

Browse files
authored
Merge pull request #53 from jamesob/createwallet-fix
0.3.0 release
2 parents 1f4abf5 + b7e4c56 commit 3a8395c

File tree

3 files changed

+148
-67
lines changed

3 files changed

+148
-67
lines changed

bin/sign_release

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#!/usr/bin/bash
22

3-
./bin/compile
43
VERSION=$(./coldcore --version | cut -d' ' -f2)
54
ASCNAME="sigs/coldcore-${VERSION}.asc"
65
MSG=$(cat <(sha256sum coldcore) <(echo $VERSION))

coldcore

Lines changed: 128 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010
1111
# TODO
1212
13-
- [ ] add wallet name
1413
- [ ] add version birthday to new config
1514
- [ ] allow manual coin selection when sending
16-
- [ ] address labeling
1715
- [ ] implement scrolling in the curses balance panel
1816
- [ ] implement --json, --csv
1917
- [ ] implement command-on-monitor
@@ -59,6 +57,9 @@ from typing import IO, Optional as Op
5957
from configparser import ConfigParser
6058

6159

60+
__VERSION__ = "0.3.0"
61+
62+
6263
# --- command line parsing ------------------------------------------------------------
6364
# -------------------------------------------------------------------------------------
6465

@@ -332,6 +333,10 @@ class JSONRPCError(Exception):
332333
)
333334
self.error = rpc_error
334335

336+
@property
337+
def code(self) -> int:
338+
return int(self.error["code"])
339+
335340

336341
class BitcoinRPC(object):
337342
"""Base JSON-RPC proxy class. Contains only private methods; do not use
@@ -1004,65 +1009,7 @@ def run_setup(config) -> t.Tuple[t.Any, t.Any]:
10041009
done(f"wrote config to {config.loaded_from}")
10051010
p()
10061011

1007-
section("wallet setup in Core")
1008-
rpc_wallet_create(rpc, wallet)
1009-
done(f"created wallet {yellow(wallet.name)} in Core as watch-only")
1010-
1011-
rpcw = config.rpc(wallet)
1012-
rpcw.importmulti(*wallet.importmulti_args())
1013-
done("imported descriptors 0/* and 1/* (change)")
1014-
1015-
scan_result = {} # type: ignore
1016-
scan_thread = threading.Thread(
1017-
target=_run_scantxoutset,
1018-
args=(config.rpc(wallet), wallet.scantxoutset_args(), scan_result),
1019-
)
1020-
scan_thread.start()
1021-
1022-
p()
1023-
section("scanning the chain for balance and history")
1024-
while scan_thread.is_alive():
1025-
spin("scanning the UTXO set for your balance (few minutes) ")
1026-
time.sleep(0.2)
1027-
1028-
p()
1029-
done("scan of UTXO set complete!")
1030-
1031-
# TODO this will fail if we timed out
1032-
unspents = scan_result["result"]["unspents"]
1033-
bal = sum([i["amount"] for i in unspents])
1034-
bal_str = yellow(bold(f"{bal} BTC"))
1035-
bal_count = yellow(bold(f"{len(unspents)} UTXOs"))
1036-
blank(f"found an existing balance of {yellow(bal_str)} across {yellow(bal_count)}")
1037-
1038-
if unspents:
1039-
rescan_begin_height = min([i["height"] for i in unspents])
1040-
p()
1041-
blank(
1042-
f"beginning chain rescan from height {bold(str(rescan_begin_height))} "
1043-
f"(minutes to hours)"
1044-
)
1045-
blank(" this allows us to find transactions associated with your coins\n")
1046-
rescan_thread = threading.Thread(
1047-
target=_run_rescan,
1048-
args=(config.rpc(wallet), rescan_begin_height),
1049-
daemon=True,
1050-
)
1051-
rescan_thread.start()
1052-
1053-
time.sleep(2)
1054-
1055-
scan_info = rpcw.getwalletinfo()["scanning"]
1056-
while scan_info:
1057-
spin(f"scan progress: {scan_info['progress'] * 100:.2f}% ")
1058-
time.sleep(0.5)
1059-
scan_info = rpcw.getwalletinfo()["scanning"]
1060-
1061-
name = yellow(wallet.name)
1062-
p()
1063-
done(f"scan complete. wallet {name} ready to use.")
1064-
info(f"Hint: check out your UTXOs with `coldcore -w {wallet.name} balance`")
1065-
1012+
rpcw = init_wallet_in_core(config, rpc, wallet)
10661013
p()
10671014

10681015
got = inp("do you want to perform some test transactions? [Y/n] ").lower()
@@ -1889,8 +1836,6 @@ def start_ui(config, wallet_configs, action=None):
18891836
# --- main/CLI ------------------------------------------------------------------------
18901837
# -------------------------------------------------------------------------------------
18911838

1892-
__VERSION__ = "0.2.0-beta"
1893-
18941839
root_logger = logging.getLogger()
18951840
logger = logging.getLogger("main")
18961841

@@ -2124,7 +2069,97 @@ def newaddr(num: int = 1, clip: ClipArg = False): # type: ignore
21242069
@cli.cmd
21252070
def ui():
21262071
config, walls = _get_config(require_wallets=False)
2127-
start_ui(config, walls)
2072+
try:
2073+
start_ui(config, walls)
2074+
except JSONRPCError as e:
2075+
if e.code == -18:
2076+
print()
2077+
print("Wallet not found - are you using a new instance of bitcoind?")
2078+
print("If so, reinitialize with `coldcore reinit-wallet`")
2079+
sys.exit(1)
2080+
else:
2081+
raise
2082+
2083+
2084+
@cli.cmd
2085+
def reinit_wallet():
2086+
"""
2087+
Reinitialize the wallet on an instance of bitcoind which hasn't seen it before.
2088+
"""
2089+
config, walls = _get_config(require_wallets=False)
2090+
assert walls
2091+
rpc = discover_rpc(config)
2092+
assert rpc
2093+
init_wallet_in_core(config, rpc, walls[0])
2094+
2095+
2096+
def init_wallet_in_core(config, rpc, wallet) -> BitcoinRPC:
2097+
"""
2098+
Initialize a wallet in core useing createwallet and scan for its balance and
2099+
history.
2100+
"""
2101+
F.section("wallet setup in Core")
2102+
rpc_wallet_create(rpc, wallet)
2103+
F.done(f"created wallet {yellow(wallet.name)} in Core as watch-only")
2104+
2105+
rpcw = config.rpc(wallet)
2106+
rpcw.importmulti(*wallet.importmulti_args())
2107+
F.done("imported descriptors 0/* and 1/* (change)")
2108+
2109+
scan_result = {} # type: ignore
2110+
scan_thread = threading.Thread(
2111+
target=_run_scantxoutset,
2112+
args=(config.rpc(wallet), wallet.scantxoutset_args(), scan_result),
2113+
)
2114+
scan_thread.start()
2115+
2116+
print()
2117+
F.section("scanning the chain for balance and history")
2118+
while scan_thread.is_alive():
2119+
F.spin("scanning the UTXO set for your balance (few minutes) ")
2120+
time.sleep(0.2)
2121+
2122+
print()
2123+
F.done("scan of UTXO set complete!")
2124+
2125+
# TODO this will fail if we timed out
2126+
unspents = scan_result["result"]["unspents"]
2127+
bal = sum([i["amount"] for i in unspents])
2128+
bal_str = yellow(bold(f"{bal} BTC"))
2129+
bal_count = yellow(bold(f"{len(unspents)} UTXOs"))
2130+
F.blank(
2131+
f"found an existing balance of {yellow(bal_str)} across {yellow(bal_count)}"
2132+
)
2133+
2134+
if unspents:
2135+
rescan_begin_height = min([i["height"] for i in unspents])
2136+
print()
2137+
F.blank(
2138+
f"beginning chain rescan from height {bold(str(rescan_begin_height))} "
2139+
f"(minutes to hours)"
2140+
)
2141+
F.blank(" this allows us to find transactions associated with your coins\n")
2142+
rescan_thread = threading.Thread(
2143+
target=_run_rescan,
2144+
args=(config.rpc(wallet), rescan_begin_height),
2145+
daemon=True,
2146+
)
2147+
rescan_thread.start()
2148+
2149+
time.sleep(2)
2150+
2151+
scan_info = rpcw.getwalletinfo()["scanning"]
2152+
while scan_info:
2153+
F.spin(f"scan progress: {scan_info['progress'] * 100:.2f}% ")
2154+
time.sleep(0.5)
2155+
scan_info = rpcw.getwalletinfo()["scanning"]
2156+
2157+
name = yellow(wallet.name)
2158+
print()
2159+
F.done(f"scan complete. wallet {name} ready to use.")
2160+
F.info(f"Hint: check out your UTXOs with `coldcore -w {wallet.name} balance`")
2161+
2162+
return rpcw
21282163

21292164

21302165
@cli.main
@@ -2601,7 +2636,8 @@ def discover_rpc(
26012636
def _is_already_loaded_err(e: JSONRPCError) -> bool:
26022637
msg = str(e).lower()
26032638
return (
2604-
("already loaded" in msg)
2639+
e.code == -4
2640+
or ("already loaded" in msg)
26052641
or ("duplicate -wallet filename" in msg)
26062642
or ("database already exists" in msg)
26072643
)
@@ -2661,6 +2697,16 @@ def _get_rpc_inner(
26612697
)
26622698

26632699

2700+
def get_node_version(rpc: BitcoinRPC) -> t.Tuple[int, int, int]:
2701+
"""E.g. (22, 99, 0)."""
2702+
netinfo = rpc.getnetworkinfo()
2703+
ver = re.match(r"/Satoshi:(\d+)\.(\d+)\.(\d+)/", netinfo["subversion"])
2704+
assert ver
2705+
groups = [int(i) for i in ver.groups()]
2706+
assert len(groups) == 3
2707+
return (groups[0], groups[1], groups[2])
2708+
2709+
26642710
# --- Wallet/transaction utilities --------------------------------------------
26652711
# -----------------------------------------------------------------------------
26662712

@@ -2682,8 +2728,24 @@ def _sh(*args, **kwargs) -> subprocess.CompletedProcess:
26822728

26832729

26842730
def rpc_wallet_create(rpc: BitcoinRPC, wall: Wallet):
2731+
node_ver = get_node_version(rpc)
26852732
try:
2686-
rpc.createwallet(wall.bitcoind_name, True)
2733+
if node_ver < (22, 99, 0):
2734+
rpc.createwallet(
2735+
wall.bitcoind_name,
2736+
True, # disable_private_keys
2737+
)
2738+
else:
2739+
# In 22.99+ (i.e. the 23.0 release), createwallet creates descriptor wallets
2740+
# by default, which are incompatible with importmulti.
2741+
rpc.createwallet(
2742+
wall.bitcoind_name,
2743+
True, # disable_private_keys
2744+
True, # blank
2745+
None, # passphrase
2746+
False, # avoid_reuse
2747+
False, # descriptors
2748+
)
26872749
except JSONRPCError as e:
26882750
if not _is_already_loaded_err(e):
26892751
# Wallet already exists; ok.

sigs/coldcore-0.3.0.asc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-----BEGIN PGP SIGNED MESSAGE-----
2+
Hash: SHA512
3+
4+
acb85a13d3b66e2318a443ceb442dad6fbd02825b39c0ec2a77fe68ea1a8232e coldcore 0.3.0
5+
-----BEGIN PGP SIGNATURE-----
6+
7+
iQIzBAEBCgAdFiEEGNRVI1NPYuZCSIrGepNdrbLETwUFAmIfiToACgkQepNdrbLE
8+
TwWang/+PuS4GVFWXR53WfkWO3qXd23864CK1pirbAZlcUuWcNAqoqimt+4PMEWV
9+
6kU25HiARGsaD4pn5g0kX6OaORslxXSB7T8Dv7yEhjJjDNE9+oRB7YJ3KratiYyv
10+
Ri0dGVH0s5RjbgiiNNhiJ8Vi1/GitZWfmw+9isTjGIu/5iTOiMOKgGwU0flbWZLp
11+
C6+sElh88grHa9KBf8UjuXcc9zuFkUSJq8W4nfrsFwaUu5KsdfAFWAq1zW+BX1X1
12+
DR2kcCp8OeyEDAjQJCIiA9B6k6zCbgc1gA9256LOo22JN2nnSpAYFXe5Xeir9X+G
13+
Yrl+HyW+bCQnQFvE6Sak7quxcTnGv1EgPf10TCPmyGWYwo+B/TotEcE6db8PwoOs
14+
lsOyYnSWHA0oHGH3uf1wpUQ51vYnNUAiAx5hXXaEZb0ao71a8L45V1CKLxWqkbrO
15+
hsxSftGMy84R1PduN656BIfaQbloi9Pr/UDe/Gea78i7yWZ0BziP8xVsMid07QPE
16+
4dxhwpx4flnDFkNhDHsARpZEPVVy2K4oFdFtTWijXVPFTcOXpkHLsOHztNPj+75m
17+
BZXqRZOrTYoglZ+/7g6W/IfGaeDtFU8ojqtuJWPXTT6sd3XoMD+qwjGqg2ytuVXo
18+
esLrvAJp2LP19XPJUJyZwH7lqB4UVaG6BQVO0p4Rc/jx7Ac57xw=
19+
=4/f7
20+
-----END PGP SIGNATURE-----

0 commit comments

Comments
 (0)