Skip to content

Commit 6ee8e08

Browse files
committed
minor cleanup throughout codebase
1 parent c85ff59 commit 6ee8e08

13 files changed

Lines changed: 189 additions & 180 deletions

File tree

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ python-bitcoin-utils
33

44
This is a bitcoin library that provides tools/utilities to interact with the Bitcoin network. One of the primary goals of the library is to explain the low-level details of Bitcoin. The code is easy to read and properly documented explaining in detail all the thorny aspects of the implementation. It is a low-level library which assumes some high-level understanding of how Bitcoin works. In the future this might change.
55

6-
The library (v0.8.2) currently supports private/public keys, all type of addresses and creation of any transaction, incl. segwit and taproot, with all SIGHASH types. All script op codes are included. Block parsing is also handled so you can read raw blocks directly. PSBT (BIP-174) is supported. Extra functionality will be added continuously and the documentation will be improved as the work progresses.
6+
The library (v0.8.3) currently supports private/public keys, all type of addresses and creation of any transaction, incl. segwit and taproot, with all SIGHASH types. All script op codes are included. Block parsing is also handled so you can read raw blocks directly. PSBT (BIP-174) is supported. Extra functionality will be added continuously and the documentation will be improved as the work progresses.
77

88
The API documentation can be build with Sphinx but is also available as a PDF for convenience. One can currently use the library for experimenting and learning the inner workings of Bitcoin. It is not meant for production yet and parts of the API might be updated with new versions.
99

bitcoinutils/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.8.2"
1+
__version__ = "0.8.3"

bitcoinutils/block.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
from bitcoinutils.constants import HEADER_SIZE, BLOCK_MAGIC_NUMBER
1111

12-
import os
13-
1412

1513
class BlockHeader:
1614
"""
@@ -56,6 +54,8 @@ class BlockHeader:
5654
Retrieves the nonce used for mining to achieve the block's proof of work.
5755
format_timestamp()
5856
Formats the timestamp into a human-readable UTC datetime string.
57+
get_target_hex()
58+
Decodes target bits into the full proof-of-work target.
5959
"""
6060

6161
def __init__(
@@ -200,7 +200,7 @@ def format_timestamp(self):
200200
utc_time = datetime.fromtimestamp(self.timestamp, timezone.utc)
201201
return utc_time.strftime("%Y-%m-%d %H:%M:%S UTC")
202202

203-
def get_target_bits(self):
203+
def get_target_hex(self):
204204
"""
205205
Decodes the compact representation of the target bits into the full target hash
206206
that a block's hash must be less than or equal to, in order to solve the block.
@@ -210,7 +210,11 @@ def get_target_bits(self):
210210
the full 256-bit target hash used in the proof of work.
211211
"""
212212

213-
# Extract the exponent (first byte) and coefficient (last three bytes) from the target_bits
213+
if self.target_bits is None:
214+
return None
215+
216+
# Extract the exponent (first byte) and coefficient (last three bytes)
217+
# from the target_bits.
214218
exponent = self.target_bits >> 24
215219
coefficient = self.target_bits & 0xFFFFFF
216220

@@ -358,6 +362,10 @@ def from_raw(rawhexdata: Union[str, bytes]):
358362
rawdata = rawhexdata
359363
else:
360364
raise TypeError("Input must be a hexadecimal string or bytes")
365+
366+
if len(rawdata) < 8 + HEADER_SIZE + 1:
367+
raise ValueError("Block data is too short.")
368+
361369
magic = rawdata[0:4]
362370
block_size = struct.unpack("<I", rawdata[4:8])[0]
363371
block_size = block_size
@@ -375,15 +383,12 @@ def from_raw(rawhexdata: Union[str, bytes]):
375383
rawdata[current_offset : current_offset + tx_length].hex()
376384
)
377385
)
378-
temp = Transaction.from_raw(
379-
rawdata[current_offset : current_offset + tx_length].hex()
380-
)
381386
current_offset += tx_length
382387

383388
except Exception as e:
384-
print(e)
385-
print(i, transaction_count)
386-
break
389+
raise ValueError(
390+
f"Could not parse transaction {i + 1} of {transaction_count}"
391+
) from e
387392

388393
return Block(magic, block_size, header, transaction_count, transactions)
389394

bitcoinutils/keys.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,11 +1404,3 @@ def is_odd(self) -> bool:
14041404
False otherwise."""
14051405

14061406
return self.odd
1407-
1408-
1409-
def main():
1410-
pass
1411-
1412-
1413-
if __name__ == "__main__":
1414-
main()

bitcoinutils/psbt.py

Lines changed: 8 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,14 @@
2020
import base64
2121

2222
from bitcoinutils.constants import SIGHASH_ALL
23-
from bitcoinutils.script import Script
23+
from bitcoinutils.script import (
24+
Script,
25+
is_p2pkh as _is_p2pkh,
26+
is_p2sh as _is_p2sh,
27+
is_p2wpkh as _is_p2wpkh,
28+
is_p2wsh as _is_p2wsh,
29+
is_p2tr as _is_p2tr,
30+
)
2431
from bitcoinutils.transactions import (
2532
Transaction,
2633
TxInput,
@@ -93,64 +100,6 @@ def _validate_pubkey_length(pubkey: bytes, context: str) -> None:
93100
)
94101

95102

96-
# ---------------------------------------------------------------------------
97-
# Script type detection helpers
98-
# ---------------------------------------------------------------------------
99-
100-
def _is_p2pkh(script: Script) -> bool:
101-
"""OP_DUP OP_HASH160 <20-byte-hash> OP_EQUALVERIFY OP_CHECKSIG"""
102-
s = script.script
103-
return (
104-
len(s) == 5
105-
and s[0] == "OP_DUP"
106-
and s[1] == "OP_HASH160"
107-
and isinstance(s[2], str) and len(s[2]) == 40
108-
and s[3] == "OP_EQUALVERIFY"
109-
and s[4] == "OP_CHECKSIG"
110-
)
111-
112-
113-
def _is_p2sh(script: Script) -> bool:
114-
"""OP_HASH160 <20-byte-hash> OP_EQUAL"""
115-
s = script.script
116-
return (
117-
len(s) == 3
118-
and s[0] == "OP_HASH160"
119-
and isinstance(s[1], str) and len(s[1]) == 40
120-
and s[2] == "OP_EQUAL"
121-
)
122-
123-
124-
def _is_p2wpkh(script: Script) -> bool:
125-
"""OP_0 <20-byte-hash>"""
126-
s = script.script
127-
return (
128-
len(s) == 2
129-
and s[0] == "OP_0"
130-
and isinstance(s[1], str) and len(s[1]) == 40
131-
)
132-
133-
134-
def _is_p2wsh(script: Script) -> bool:
135-
"""OP_0 <32-byte-hash>"""
136-
s = script.script
137-
return (
138-
len(s) == 2
139-
and s[0] == "OP_0"
140-
and isinstance(s[1], str) and len(s[1]) == 64
141-
)
142-
143-
144-
def _is_p2tr(script: Script) -> bool:
145-
"""OP_1 <32-byte-key>"""
146-
s = script.script
147-
return (
148-
len(s) == 2
149-
and s[0] == "OP_1"
150-
and isinstance(s[1], str) and len(s[1]) == 64
151-
)
152-
153-
154103
# Map OP_n strings to integer n
155104
_OP_N_MAP = {f"OP_{i}": i for i in range(1, 17)}
156105

bitcoinutils/script.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,4 +452,68 @@ def __repr__(self) -> str:
452452
def __eq__(self, _other: object) -> bool:
453453
if not isinstance(_other, Script):
454454
return False
455-
return self.script == _other.script
455+
return self.script == _other.script
456+
457+
458+
def is_p2pkh(script: Script) -> bool:
459+
"""Returns True for a P2PKH scriptPubKey."""
460+
461+
s = script.script
462+
return (
463+
len(s) == 5
464+
and s[0] == "OP_DUP"
465+
and s[1] == "OP_HASH160"
466+
and isinstance(s[2], str)
467+
and len(s[2]) == 40
468+
and s[3] == "OP_EQUALVERIFY"
469+
and s[4] == "OP_CHECKSIG"
470+
)
471+
472+
473+
def is_p2sh(script: Script) -> bool:
474+
"""Returns True for OP_HASH160 <20-byte-hash> OP_EQUAL."""
475+
476+
s = script.script
477+
return (
478+
len(s) == 3
479+
and s[0] == "OP_HASH160"
480+
and isinstance(s[1], str)
481+
and len(s[1]) == 40
482+
and s[2] == "OP_EQUAL"
483+
)
484+
485+
486+
def is_p2wpkh(script: Script) -> bool:
487+
"""Returns True for OP_0 <20-byte-hash>."""
488+
489+
s = script.script
490+
return (
491+
len(s) == 2
492+
and s[0] == "OP_0"
493+
and isinstance(s[1], str)
494+
and len(s[1]) == 40
495+
)
496+
497+
498+
def is_p2wsh(script: Script) -> bool:
499+
"""Returns True for OP_0 <32-byte-hash>."""
500+
501+
s = script.script
502+
return (
503+
len(s) == 2
504+
and s[0] == "OP_0"
505+
and isinstance(s[1], str)
506+
and len(s[1]) == 64
507+
)
508+
509+
510+
def is_p2tr(script: Script) -> bool:
511+
"""Returns True for OP_1 <32-byte-key>."""
512+
513+
s = script.script
514+
return (
515+
len(s) == 2
516+
and s[0] == "OP_1"
517+
and isinstance(s[1], str)
518+
and len(s[1]) == 64
519+
)

bitcoinutils/setup.py

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616

1717
def setup(network: str = "testnet") -> str:
1818
global NETWORK
19+
if network not in networks:
20+
supported = ", ".join(sorted(networks))
21+
raise ValueError(
22+
f"Unknown network '{network}'. Supported networks: {supported}"
23+
)
1924
NETWORK = network
2025
return NETWORK
2126

@@ -26,40 +31,20 @@ def get_network() -> str:
2631

2732

2833
def is_mainnet() -> bool:
29-
global NETWORK
30-
if NETWORK == "mainnet":
31-
return True
32-
else:
33-
return False
34+
return NETWORK == "mainnet"
3435

3536

3637
def is_testnet() -> bool:
37-
global NETWORK
38-
if NETWORK == "testnet":
39-
return True
40-
else:
41-
return False
38+
return NETWORK == "testnet"
4239

4340

4441
def is_testnet4() -> bool:
45-
global NETWORK
46-
if NETWORK == "testnet4":
47-
return True
48-
else:
49-
return False
42+
return NETWORK == "testnet4"
5043

5144

5245
def is_signet() -> bool:
53-
global NETWORK
54-
if NETWORK == "signet":
55-
return True
56-
else:
57-
return False
46+
return NETWORK == "signet"
5847

5948

6049
def is_regtest() -> bool:
61-
global NETWORK
62-
if NETWORK == "regtest":
63-
return True
64-
else:
65-
return False
50+
return NETWORK == "regtest"

0 commit comments

Comments
 (0)