From 2c1457a135093c7d8a4a134fdad6501a181ca3e2 Mon Sep 17 00:00:00 2001 From: 4tochka Date: Fri, 15 Mar 2019 01:36:25 +0400 Subject: [PATCH] cleaning code --- pybtc/__init__.py | 9 +- pybtc/address.py | 18 +++- pybtc/block.py | 18 ++-- pybtc/constants.py | 28 +++--- pybtc/functions/address.py | 23 +++-- pybtc/functions/bip32.py | 24 +++-- pybtc/functions/bip39_mnemonic.py | 18 ++-- pybtc/functions/block.py | 21 +++-- pybtc/functions/encode.py | 32 ++++--- pybtc/functions/hash.py | 44 ++++----- pybtc/functions/key.py | 31 +++---- pybtc/functions/script.py | 117 ++++++++++++----------- pybtc/functions/tools.py | 75 +++++++-------- pybtc/test/__init__.py | 8 +- pybtc/test/block.py | 6 +- pybtc/transaction.py | 148 +++++++++++++++++------------- 16 files changed, 337 insertions(+), 283 deletions(-) diff --git a/pybtc/__init__.py b/pybtc/__init__.py index 7a69692..a8e288c 100644 --- a/pybtc/__init__.py +++ b/pybtc/__init__.py @@ -1,6 +1,9 @@ -from .functions import * -from .opcodes import * -from .consensus import * +from pybtc.constants import * +from pybtc.opcodes import * +from pybtc.consensus import * +from pybtc.functions import * + + from .transaction import * from .block import * from .address import * diff --git a/pybtc/address.py b/pybtc/address.py index 0a61a73..bd233ab 100644 --- a/pybtc/address.py +++ b/pybtc/address.py @@ -1,5 +1,15 @@ -from .functions import * - +from pybtc.constants import * +from pybtc.opcodes import * +from pybtc.functions.tools import bytes_from_hex, int_to_var_int +from pybtc.functions.script import op_push_data, decode_script +from pybtc.functions.hash import hash160, sha256 +from pybtc.functions.address import hash_to_address, public_key_to_p2sh_p2wpkh_script +from pybtc.functions.key import (create_private_key, + private_key_to_wif, + is_wif_valid, + wif_to_private_key, + is_public_key_valid, + private_to_public_key) class PrivateKey(): """ @@ -31,7 +41,7 @@ class PrivateKey(): else: if isinstance(key, str): try: - key = bytes.fromhex(key) + key = bytes_from_hex(key) except: pass if isinstance(key, bytes): @@ -90,7 +100,7 @@ class PublicKey(): def __init__(self, key, compressed=True, testnet=False): if isinstance(key, str): try: - key = bytes.fromhex(key) + key = bytes_from_hex(key) except: if is_wif_valid(key): key = PrivateKey(key) diff --git a/pybtc/block.py b/pybtc/block.py index 175e2ea..1f1be47 100644 --- a/pybtc/block.py +++ b/pybtc/block.py @@ -1,6 +1,10 @@ -from .transaction import Transaction -from struct import unpack -from .functions import * +from struct import unpack, pack +from io import BytesIO +from pybtc.functions.block import bits_to_target, target_to_difficulty +from pybtc.functions.hash import double_sha256 +from pybtc.functions.tools import var_int_to_int, read_var_int, var_int_len, rh2s +from pybtc.transaction import Transaction + class Block(dict): def __init__(self, raw_block=None, format="decoded", version=536870912, testnet=False): @@ -11,7 +15,7 @@ class Block(dict): self["header"] = None self["hash"] = None self["version"] = version - self["versionHex"] = struct.pack(">L", version).hex() + self["versionHex"] = pack(">L", version).hex() self["previousBlockHash"] = None self["merkleRoot"] = None self["tx"] = dict() @@ -32,7 +36,7 @@ class Block(dict): s = self.get_stream(raw_block) self["format"] = "raw" self["version"] = unpack("L", self["version"]).hex() + self["versionHex"] = pack(">L", self["version"]).hex() self["previousBlockHash"] = s.read(32) self["merkleRoot"] = s.read(32) self["time"] = unpack("= HARDENED_KEY else pub, struct.pack(">L", i))) + s = hmac_sha512(c, b"%s%s" % (k if i >= HARDENED_KEY else pub, pack(">L", i))) p_int = int.from_bytes(s[:32],byteorder='big') if p_int >= ECDSA_SEC256K1_ORDER: return None @@ -121,7 +127,7 @@ def derive_child_xprivate_key(xprivate_key, i): return b"".join([xprivate_key[:4], bytes([depth]), fingerprint, - struct.pack(">L", i), + pack(">L", i), s[32:], b'\x00', key]) @@ -136,24 +142,24 @@ def derive_child_xpublic_key(xpublic_key, i): raise ValueError("path depth should be <= 255") if i >= HARDENED_KEY: raise ValueError("derivation from extended public key impossible") - s = hmac_sha512(c, k + struct.pack(">L", i)) + s = hmac_sha512(c, k + pack(">L", i)) if int.from_bytes(s[:32], byteorder='big') >= ECDSA_SEC256K1_ORDER: return None pubkey_ptr = ffi.new('secp256k1_pubkey *') - if not secp256k1.secp256k1_ec_pubkey_parse(ECDSA_CONTEXT_VERIFY, pubkey_ptr, k, len(k)): + if not lib.secp256k1_ec_pubkey_parse(ECDSA_CONTEXT_VERIFY, pubkey_ptr, k, len(k)): raise RuntimeError("secp256k1 parse public key operation failed") - if not secp256k1.secp256k1_ec_pubkey_tweak_add(ECDSA_CONTEXT_ALL, pubkey_ptr, s[:32]): + if not lib.secp256k1_ec_pubkey_tweak_add(ECDSA_CONTEXT_ALL, pubkey_ptr, s[:32]): raise RuntimeError("secp256k1 parse tweak addition operation failed") pubkey = ffi.new('char [%d]' % 33) outlen = ffi.new('size_t *', 33) - if not secp256k1.secp256k1_ec_pubkey_serialize(ECDSA_CONTEXT_VERIFY, pubkey, outlen, pubkey_ptr, EC_COMPRESSED): + if not lib.secp256k1_ec_pubkey_serialize(ECDSA_CONTEXT_VERIFY, pubkey, outlen, pubkey_ptr, EC_COMPRESSED): raise RuntimeError("secp256k1 serialize public key operation failed") pk = bytes(ffi.buffer(pubkey, 33)) print(len(pk)) return b"".join([xpublic_key[:4], bytes([depth]), fingerprint, - struct.pack(">L", i), + pack(">L", i), s[32:], pk]) diff --git a/pybtc/functions/bip39_mnemonic.py b/pybtc/functions/bip39_mnemonic.py index af03b3d..43ad391 100644 --- a/pybtc/functions/bip39_mnemonic.py +++ b/pybtc/functions/bip39_mnemonic.py @@ -1,14 +1,8 @@ -import os -import sys -import time -parentPath = os.path.abspath("../..") -if parentPath not in sys.path: - sys.path.insert(0, parentPath) - from pybtc.constants import * -from .hash import * -from hashlib import pbkdf2_hmac - +import time +import hashlib +from pybtc.functions.hash import sha256 +from pybtc.functions.tools import int_from_bytes def generate_entropy(strength=256, hex=True): """ @@ -27,7 +21,7 @@ def generate_entropy(strength=256, hex=True): while i: h = hashlib.sha256(h).digest() i -= 1 - if not i and int.from_bytes(h, byteorder="big") > ECDSA_SEC256K1_ORDER: + if not i and int_from_bytes(h, byteorder="big") > ECDSA_SEC256K1_ORDER: i += 1 return h[:int(strength/8)] if not hex else h[:int(strength/8)].hex() @@ -139,5 +133,5 @@ def mnemonic_to_seed(mnemonic, passphrase="", hex=True): if not isinstance(passphrase, str): raise TypeError("mnemonic should be string") - seed = pbkdf2_hmac('sha512', mnemonic.encode(), ("mnemonic"+passphrase).encode(), 2048) + seed = hashlib.pbkdf2_hmac('sha512', mnemonic.encode(), ("mnemonic"+passphrase).encode(), 2048) return seed if not hex else seed.hex() diff --git a/pybtc/functions/block.py b/pybtc/functions/block.py index 39a4716..1cf84a2 100644 --- a/pybtc/functions/block.py +++ b/pybtc/functions/block.py @@ -1,3 +1,5 @@ +from pybtc.functions.tools import s2rh, bytes_from_hex, int_from_bytes +from pybtc.functions.hash import double_sha256 def merkle_root(tx_hash_list, hex=True): """ @@ -12,13 +14,14 @@ def merkle_root(tx_hash_list, hex=True): return tx_hash_list[0] while True: new_hash_list = list() + append = new_hash_list.append while tx_hash_list: h1 = tx_hash_list.pop(0) try: h2 = tx_hash_list.pop(0) except: h2 = h1 - new_hash_list.append(double_sha256(h1 + h2)) + append(double_sha256(h1 + h2)) if len(new_hash_list) > 1: tx_hash_list = new_hash_list else: @@ -38,21 +41,23 @@ def merkle_branches(tx_hash_list, hex=True): if len(tx_hash_list) == 1: return [] tx_hash_list.pop(0) + branches_append = branches.append while True: - branches.append(tx_hash_list.pop(0)) + branches_append(tx_hash_list.pop(0)) new_hash_list = list() + new_hash_list_append = new_hash_list.append while tx_hash_list: h1 = tx_hash_list.pop(0) try: h2 = tx_hash_list.pop(0) except: h2 = h1 - new_hash_list.append(double_sha256(h1 + h2)) + new_hash_list_append(double_sha256(h1 + h2)) if len(new_hash_list) > 1: tx_hash_list = new_hash_list else: if new_hash_list: - branches.append(new_hash_list.pop(0)) + branches_append(new_hash_list.pop(0)) return branches if not hex else [h.hex() for h in branches] @@ -65,10 +70,10 @@ def merkleroot_from_branches(merkle_branches, coinbase_hash, hex=True): :param hex: (optional) If set to True return result in HEX format, by default is True. :return: merkle root in bytes or HEX encoded string corresponding hex flag. """ - merkle_root = coinbase_hash if not isinstance(coinbase_hash, str) else bytes.fromhex(coinbase_hash) + merkle_root = coinbase_hash if not isinstance(coinbase_hash, str) else bytes_from_hex(coinbase_hash) for h in merkle_branches: if type(h) == str: - h = bytes.fromhex(h) + h = bytes_from_hex(h) merkle_root = double_sha256(merkle_root + h) return merkle_root if not hex else merkle_root.hex() @@ -84,9 +89,9 @@ def bits_to_target(bits): :return: integer. """ if type(bits) == str: - bits = bytes.fromhex(bits) + bits = bytes_from_hex(bits) if type(bits) == bytes: - return int.from_bytes(bits[1:], 'big') * (2 ** (8 * (bits[0] - 3))) + return int_from_bytes(bits[1:], 'big') * (2 ** (8 * (bits[0] - 3))) else: shift = bits >> 24 target = (bits & 0xffffff) * (1 << (8 * (shift - 3))) diff --git a/pybtc/functions/encode.py b/pybtc/functions/encode.py index 2947c0c..d26f3a5 100644 --- a/pybtc/functions/encode.py +++ b/pybtc/functions/encode.py @@ -1,4 +1,5 @@ -from .hash import double_sha256 +from pybtc.functions.hash import double_sha256 +from pybtc.functions.tools import bytes_from_hex b58_digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' base32charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" @@ -19,6 +20,7 @@ def rebasebits(data, frombits, tobits, pad=True): acc = 0 bits = 0 ret = bytearray() + append = ret.append maxv = (1 << tobits) - 1 max_acc = (1 << (frombits + tobits - 1)) - 1 for value in data: @@ -28,10 +30,10 @@ def rebasebits(data, frombits, tobits, pad=True): bits += frombits while bits >= tobits: bits -= tobits - ret.append((acc >> bits) & maxv) + append((acc >> bits) & maxv) if pad: if bits: - ret.append((acc << (tobits - bits)) & maxv) + append((acc << (tobits - bits)) & maxv) elif bits >= frombits or ((acc << (tobits - bits)) & maxv): raise ValueError("invalid padding") return ret @@ -46,12 +48,12 @@ def rebase_8_to_5(data, pad = True): def rebase_32_to_5(data): - if type(data) == bytes: + if isinstance(data, bytes): data = data.decode() b = bytearray() + append = b.append try: - for i in data: - b.append(int_base32_map[i]) + [append(int_base32_map[i]) for i in data] except: raise Exception("Non base32 characters") return b @@ -59,8 +61,8 @@ def rebase_32_to_5(data): def rebase_5_to_32(data, bytes = True): r = bytearray() - for i in data: - r.append(base32_int_map[i]) + append = r.append + [append(base32_int_map[i]) for i in data] return r.decode() if not bytes else r @@ -80,13 +82,14 @@ def encode_base58(b): """Encode bytes to a base58-encoded string""" # Convert big-endian bytes to integer - n= int('0x0' + b.hex(), 16) + n= int('0x0%s' % b.hex(), 16) # Divide that integer into bas58 res = [] + append = res.append while n > 0: n, r = divmod(n, 58) - res.append(b58_digits[r]) + append(b58_digits[r]) res = ''.join(res[::-1]) # Encode leading zeros as base58 zeros czero = 0 @@ -114,8 +117,8 @@ def decode_base58(s): # Convert the integer to bytes h = '%x' % n if len(h) % 2: - h = '0' + h - res = bytes.fromhex(h) + h = '0%s' % h + res = bytes_from_hex(h) # Add padding back. pad = 0 for c in s[:-1]: @@ -123,7 +126,7 @@ def decode_base58(s): pad += 1 else: break - return b'\x00' * pad + res + return b''.join((b'\x00' * pad, res)) def encode_base58_with_checksum(b): @@ -132,5 +135,6 @@ def encode_base58_with_checksum(b): def decode_base58_with_checksum(s): b = decode_base58(s) - assert double_sha256(b[:-4])[:4] == b[-4:] + if double_sha256(b[:-4])[:4] != b[-4:]: + raise Exception("invalid checksum") return b[:-4] diff --git a/pybtc/functions/hash.py b/pybtc/functions/hash.py index 399347b..e95db1b 100644 --- a/pybtc/functions/hash.py +++ b/pybtc/functions/hash.py @@ -1,43 +1,39 @@ -import hashlib +from hashlib import new as hashlib_new +from hashlib import sha256 as hashlib_sha256 +from hashlib import sha512 as hashlib_sha512 import hmac +bytes_from_hex = bytes.fromhex def sha256(h, hex=False): - if type(h) == str: - h = bytes.fromhex(h) - if hex: - return hashlib.sha256(h).hexdigest() - return hashlib.sha256(h).digest() + if isinstance(h, str): + h = bytes_from_hex(h) + return hashlib_sha256(h).hexdigest() if hex else hashlib_sha256(h).digest() def double_sha256(h, hex=False): - if type(h) == str: - h = bytes.fromhex(h) - if hex: - return sha256(sha256(h), 1) - return sha256(sha256(h)) + if isinstance(h,str): + h = bytes_from_hex(h) + return sha256(sha256(h), True) if hex else sha256(sha256(h)) def hmac_sha512(key, data, hex=False): if hex: - return hmac.new(key, data, hashlib.sha512).hexdigest() - return hmac.new(key, data, hashlib.sha512).digest() + return hmac.new(key, data, hashlib_sha512).hexdigest() + return hmac.new(key, data, hashlib_sha512).digest() def ripemd160(h, hex=False): - if type(h) == str: - h = bytes.fromhex(h) - a = hashlib.new('ripemd160') + if isinstance(h, str): + h = bytes_from_hex(h) + a = hashlib_new('ripemd160') a.update(h) - if hex: - return a.hexdigest() - return a.digest() + return a.hexdigest() if hex else a.digest() def hash160(h, hex=False): - if type(h) == str: - bytes.fromhex(h) - if hex: - return ripemd160(sha256(h), 1) - return ripemd160(sha256(h)) + if isinstance(h, str): + bytes_from_hex(h) + return ripemd160(sha256(h), True) if hex else ripemd160(sha256(h)) + diff --git a/pybtc/functions/key.py b/pybtc/functions/key.py index 68be77c..b00e81f 100644 --- a/pybtc/functions/key.py +++ b/pybtc/functions/key.py @@ -1,15 +1,14 @@ -import os -import sys -from secp256k1 import ffi -parentPath = os.path.abspath("../..") -if parentPath not in sys.path: - sys.path.insert(0, parentPath) +from secp256k1 import ffi, lib +secp256k1_ec_pubkey_create = lib.secp256k1_ec_pubkey_create +secp256k1_ec_pubkey_serialize = lib.secp256k1_ec_pubkey_serialize from pybtc.constants import * -from .encode import * -from .hash import * +from pybtc.functions.encode import encode_base58, decode_base58 +from pybtc.functions.hash import double_sha256 from .bip39_mnemonic import generate_entropy +bytes_from_hex = bytes.fromhex + def create_private_key(compressed=True, testnet=False, wif=True, hex=False): """ @@ -44,7 +43,7 @@ def private_key_to_wif(h, compressed=True, testnet=False): # uncompressed: 0x80 + [32-byte secret] + [4 bytes of Hash() of previous 33 bytes], base58 encoded. # compressed: 0x80 + [32-byte secret] + 0x01 + [4 bytes of Hash() previous 34 bytes], base58 encoded. if isinstance(h, str): - h = bytes.fromhex(h) + h = bytes_from_hex(h) if len(h) != 32 and isinstance(h, bytes): raise TypeError("private key must be a 32 bytes or hex encoded string") if testnet: @@ -67,9 +66,7 @@ def wif_to_private_key(h, hex=True): if not is_wif_valid(h): raise TypeError("invalid wif key") h = decode_base58(h) - if hex: - return h[1:33].hex() - return h[1:33] + return h[1:33].hex() if hex else h[1:33] def is_wif_valid(wif): @@ -115,23 +112,23 @@ def private_to_public_key(private_key, compressed=True, hex=True): private_key = bytes(private_key) elif isinstance(private_key, str): if not is_wif_valid(private_key): - private_key = bytes.fromhex(private_key) + private_key = bytes_from_hex(private_key) else: if private_key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX, TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX): compressed = False - private_key = wif_to_private_key(private_key, hex=0) + private_key = wif_to_private_key(private_key, hex=False) else: raise TypeError("private key must be a bytes or WIF or hex encoded string") pubkey_ptr = ffi.new('secp256k1_pubkey *') - r = secp256k1.secp256k1_ec_pubkey_create(ECDSA_CONTEXT_ALL, pubkey_ptr, private_key) + r = secp256k1_ec_pubkey_create(ECDSA_CONTEXT_ALL, pubkey_ptr, private_key) if not r: raise RuntimeError("secp256k1 error") len_key = 33 if compressed else 65 pubkey = ffi.new('char [%d]' % len_key) outlen = ffi.new('size_t *', len_key) compflag = EC_COMPRESSED if compressed else EC_UNCOMPRESSED - r = secp256k1.secp256k1_ec_pubkey_serialize(ECDSA_CONTEXT_VERIFY, pubkey, outlen, pubkey_ptr, compflag) + r = secp256k1_ec_pubkey_serialize(ECDSA_CONTEXT_VERIFY, pubkey, outlen, pubkey_ptr, compflag) pub = bytes(ffi.buffer(pubkey, len_key)) if not r: raise RuntimeError("secp256k1 error") @@ -146,7 +143,7 @@ def is_public_key_valid(key): :return: boolean. """ if isinstance(key, str): - key = bytes.fromhex(key) + key = bytes_from_hex(key) if len(key) < 33: return False elif key[0] == 0x04 and len(key) != 65: diff --git a/pybtc/functions/script.py b/pybtc/functions/script.py index 9c52fa2..8d8f546 100644 --- a/pybtc/functions/script.py +++ b/pybtc/functions/script.py @@ -1,19 +1,28 @@ -import os -import sys -from secp256k1 import ffi -parentPath = os.path.abspath("../..") -if parentPath not in sys.path: - sys.path.insert(0, parentPath) +from struct import unpack + +from secp256k1 import ffi, lib +secp256k1_ecdsa_signature_parse_der = lib.secp256k1_ecdsa_signature_parse_der +secp256k1_ec_pubkey_parse = lib.secp256k1_ec_pubkey_parse +secp256k1_ecdsa_verify = lib.secp256k1_ecdsa_verify +secp256k1_ecdsa_sign = lib.secp256k1_ecdsa_sign +secp256k1_ecdsa_signature_serialize_der = lib.secp256k1_ecdsa_signature_serialize_der +secp256k1_ecdsa_signature_serialize_compact = lib.secp256k1_ecdsa_signature_serialize_compact +secp256k1_ecdsa_recoverable_signature_parse_compact = lib.secp256k1_ecdsa_recoverable_signature_parse_compact +secp256k1_ecdsa_recover = lib.secp256k1_ecdsa_recover +secp256k1_ec_pubkey_serialize = lib.secp256k1_ec_pubkey_serialize from pybtc.opcodes import * from pybtc.constants import * -from .tools import * -from .hash import * -from .address import hash_to_address + +from pybtc.functions.tools import bytes_from_hex, int_to_bytes, get_stream +from pybtc.functions.hash import hash160, sha256 +from pybtc.functions.address import hash_to_address +from pybtc.functions.key import is_wif_valid, wif_to_private_key + def public_key_to_pubkey_script(key, hex=True): if isinstance(key, str): - key = bytes.fromhex(key) + key = bytes_from_hex(key) s = b"%s%s%s" % (bytes([len(key)]), key, OP_CHECKSIG) return s.hex() if hex else s @@ -37,7 +46,7 @@ def parse_script(script, segwit=True): return {"nType": 7, "type": "NON_STANDARD", "reqSigs": 0, "script": b""} if isinstance(script, str): try: - script = bytes.fromhex(script) + script = bytes_from_hex(script) except: pass assert isinstance(script, bytes) @@ -109,12 +118,12 @@ def parse_script(script, segwit=True): break elif script[s] == OPCODE["OP_PUSHDATA2"]: try: - s += 2 + struct.unpack(' 0: if script[s] < 0x4c and script[s]: - stack.append(script[s] + 1) + stack_append(script[s] + 1) s += script[s] + 1 elif script[s] == OPCODE["OP_PUSHDATA1"]: - stack.append(1 + script[s + 1]) + stack_append(1 + script[s + 1]) s += 1 + script[s + 1] elif script[s] == OPCODE["OP_PUSHDATA2"]: - stack.append(2 + struct.unpack('= ls: if script[k:s][:ls] == sub_script: if s - k > ls: - result.append(script[k + ls:s]) + result_append(script[k + ls:s]) t = 0 while t != s - k: t += stack.pop(0) k = s else: t = stack.pop(0) - result.append(script[k:k + t]) + result_append(script[k:k + t]) k += t if script[k:s][:ls] == sub_script: if s - k > ls: - result.append(script[k + ls:s]) + result_append(script[k + ls:s]) else: - result.append(script[k:k + ls]) + result_append(script[k:k + ls]) return b''.join(result) if not s_hex else b''.join(result).hex() @@ -296,7 +307,7 @@ def script_to_hash(script, witness=False, hex=True): :return: script in bytes or HEX encoded string corresponding to the format of target script. """ if isinstance(script, str): - s = bytes.fromhex(script) + s = bytes_from_hex(script) if witness: return sha256(script, hex) else: @@ -327,17 +338,18 @@ def get_multisig_public_keys(script): def read_opcode(stream): - b = stream.read(1) + read = stream.read + b = read(1) if not b: return None, None if b[0] <= 0x4b: - return b, stream.read(b[0]) + return b, read(b[0]) elif b[0] == OP_PUSHDATA1: - return b, stream.read(stream.read(1)[0]) + return b, read(read(1)[0]) elif b[0] == OP_PUSHDATA2: - return b, stream.read(struct.unpack("IIIIIIII', *struct.unpack('>IIIIIIII', raw_hash)[::-1])[::-1] + return pack('>IIIIIIII', * unpack('>IIIIIIII', raw_hash)[::-1])[::-1] def bytes_needed(n): @@ -45,9 +50,7 @@ def bytes_needed(n): :param n: integer. :return: integer. """ - if n == 0: - return 1 - return math.ceil(n.bit_length()/8) + return ceil(n.bit_length()/8) if n != 0 else 1 def int_to_bytes(i, byteorder='big'): @@ -69,7 +72,7 @@ def bytes_to_int(i, byteorder='big'): :param byteorder: (optional) byte order 'big' or 'little', by default 'big'. :return: integer. """ - return int.from_bytes(i, byteorder=byteorder, signed=False) + return int_from_bytes(i, byteorder=byteorder, signed=False) # variable integer @@ -82,12 +85,12 @@ def int_to_var_int(i): :return: bytes. """ if i < 0xfd: - return struct.pack('I", bn_bytes(v, have_ext)) + s = pack(b">I", bn_bytes(v, have_ext)) ext = bytearray() if have_ext: ext.append(0) @@ -285,7 +290,7 @@ def mpi2bn(s): if len(s) < 4: return None s_size = bytes(s[:4]) - v_len = struct.unpack(b">I", s_size)[0] + v_len = unpack(b">I", s_size)[0] if len(s) != (v_len + 4): return None if v_len == 0: @@ -308,9 +313,7 @@ def mpi2bn(s): def mpi2vch(s): r = s[4:] # strip size - # if r: r = r[::-1] # reverse string, converting BE->LE - # else: r=b'\x00' return r @@ -319,7 +322,7 @@ def bn2vch(v): def vch2mpi(s): - r = struct.pack(b">I", len(s)) # size + r = pack(b">I", len(s)) # size r += s[::-1] # reverse string, converting LE->BE return r @@ -335,11 +338,11 @@ def b2i(b): return vch2bn(b) def get_stream(stream): - if type(stream) != io.BytesIO: - if type(stream) == str: - stream = bytes.fromhex(stream) - if type(stream) == bytes: - stream = io.BytesIO(stream) + if not isinstance(stream, BytesIO): + if isinstance(stream, str): + stream = bytes_from_hex(stream) + if isinstance(stream, bytes): + stream = BytesIO(stream) else: raise TypeError return stream diff --git a/pybtc/test/__init__.py b/pybtc/test/__init__.py index 48b5123..1269687 100644 --- a/pybtc/test/__init__.py +++ b/pybtc/test/__init__.py @@ -1,14 +1,14 @@ from .hash_functions import * from .integer import * from .address_functions import * -from .address_class import * +from .script_functions import * from .ecdsa import * +from .mnemonic import * +from .sighash import * +from .address_class import * from .transaction_deserialize import * from .transaction_constructor import * -from .sighash import * from .block import * -from .mnemonic import * -from .script_functions import * # from .script_deserialize import * # from .create_transaction import * diff --git a/pybtc/test/block.py b/pybtc/test/block.py index 0179916..864568a 100644 --- a/pybtc/test/block.py +++ b/pybtc/test/block.py @@ -597,7 +597,7 @@ class BlockDeserializeTests(unittest.TestCase): block_c = "2000000000000000000029a1a0390376afd72db120d698c2d8ebc41c545c7d4bc2b9033c303dd3d09d455da1c587406820a4dd77c5aa3fcc546dcceb1becc639829c4fe6535e815a1a372b405cc0829701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2303f88e130068747470733a5c6170692e6269746170732e636f6d20f251bec0cb000000ffffffff02c817a804000000001976a914d4e49947b9f545218cd20389244c249d3520545d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000" block_e = "2000000000000000000029a1a0390376afd72db120d698c2d8ebc41c545c7d4bc2b9033c303dd3d09d455da1c587406820a4dd77c5aa3fcc546dcceb1becc639829c4fe65a815e531a372b405cc0829701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2303f88e130068747470733a5c6170692e6269746170732e636f6d20f251bec0cb000000ffffffff02c817a804000000001976a914d4e49947b9f545218cd20389244c249d3520545d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000" l = Block(block_a, format="decoded") - f = open('./test/raw_block.txt') + f = open('./pybtc/test/raw_block.txt') fc = f.readline() qt = time.time() bt = Block(fc[:-1], format="decoded") @@ -606,11 +606,11 @@ class BlockDeserializeTests(unittest.TestCase): import cProfile cProfile.run("import pybtc;" - "f = open('./test/raw_block.txt');" + "f = open('./pybtc/test/raw_block.txt');" "fc = f.readline();" "pybtc.Block(fc[:-1], format='decoded')") cProfile.run("import pybtc;" - "f = open('./test/raw_block.txt');" + "f = open('./pybtc/test/raw_block.txt');" "fc = f.readline();" "pybtc.Block(fc[:-1], format='raw')") # print(">>>",block.bits) diff --git a/pybtc/transaction.py b/pybtc/transaction.py index a7b3897..85e437b 100644 --- a/pybtc/transaction.py +++ b/pybtc/transaction.py @@ -1,8 +1,23 @@ - -from struct import unpack import json -from .functions import * -from .address import PrivateKey, Address, PublicKey, ScriptAddress +from struct import unpack, pack +from math import ceil +from io import BytesIO +from pybtc.constants import * +from pybtc.opcodes import * +from pybtc.functions.tools import (int_to_var_int, + read_var_int, + var_int_to_int, + rh2s, + s2rh, + bytes_from_hex, + get_stream) +from pybtc.functions.script import op_push_data, decode_script, parse_script, sign_message +from pybtc.functions.script import get_multisig_public_keys, read_opcode, is_valid_signature_encoding +from pybtc.functions.script import public_key_recovery, delete_from_script +from pybtc.functions.hash import hash160, sha256, double_sha256 +from pybtc.functions.address import hash_to_address, address_net_type, address_to_script +from pybtc.address import PrivateKey, Address, ScriptAddress, PublicKey + class Transaction(dict): @@ -53,31 +68,34 @@ class Transaction(dict): sw = sw_len = 0 stream = self.get_stream(raw_tx) start = stream.tell() - + read = stream.read + tell = stream.tell + seek = stream.seek # start deserialization - self["version"] = unpack(' 520 and input_verify): raise TypeError("script_sig invalid") @@ -394,9 +414,9 @@ class Transaction(dict): witness = [] for w in tx_in_witness: if isinstance(w, str): - witness.append(bytes.fromhex(w) if self["format"] == "raw" else w) + witness.append(bytes_from_hex(w) if self["format"] == "raw" else w) else: - witness.append(w if self["format"] == "raw" else bytes.fromhex(w)) + witness.append(w if self["format"] == "raw" else bytes_from_hex(w)) l += 1 + len(w) if len(w) >= 0x4c: l += 1 @@ -415,13 +435,13 @@ class Transaction(dict): # script_pub_key if script_pub_key: if isinstance(script_pub_key, str): - script_pub_key = bytes.fromhex(script_pub_key) + script_pub_key = bytes_from_hex(script_pub_key) if not isinstance(script_pub_key, bytes): raise TypeError("script_pub_key tx invalid") if redeem_script: if isinstance(redeem_script, str): - redeem_script = bytes.fromhex(redeem_script) + redeem_script = bytes_from_hex(redeem_script) if not isinstance(redeem_script, bytes): raise TypeError("redeem_script tx invalid") @@ -485,7 +505,7 @@ class Transaction(dict): raise Exception("unable to add output, amount value error") if script_pub_key: if isinstance(script_pub_key, str): - script_pub_key = bytes.fromhex(script_pub_key) + script_pub_key = bytes_from_hex(script_pub_key) if not isinstance(script_pub_key, bytes): raise TypeError("unable to add output, script_pub_key type error") else: @@ -920,7 +940,7 @@ class Transaction(dict): script_code = delete_from_script(script_code, BYTE_OPCODE["OP_CODESEPARATOR"]) pm = bytearray() - pm += b"%s%s" % (struct.pack(' n and (sighash_type & 31) == SIGHASH_SINGLE: continue if (sighash_type & 31) == SIGHASH_SINGLE and (n != i): @@ -964,7 +982,7 @@ class Transaction(dict): pm += b"%s%s%s" % (self["vOut"][i]["value"].to_bytes(8, 'little'), int_to_var_int(len(script_pub_key)), script_pub_key) - pm += b"%s%s" % (self["lockTime"].to_bytes(4, 'little'), struct.pack(b"