decode transaction perfomance increased
This commit is contained in:
parent
44e164e6bb
commit
3dee268133
@ -1,10 +1,8 @@
|
|||||||
from .tools import *
|
from .functions import *
|
||||||
from .opcodes import *
|
from .opcodes import *
|
||||||
from .consensus import *
|
from .consensus import *
|
||||||
from .transaction import *
|
from .transaction import *
|
||||||
from .block import *
|
from .block import *
|
||||||
from .address import *
|
from .address import *
|
||||||
from .hdwallet import *
|
from .hdwallet import *
|
||||||
from .hash import *
|
|
||||||
|
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from .tools import *
|
from .functions import *
|
||||||
|
|
||||||
|
|
||||||
class PrivateKey():
|
class PrivateKey():
|
||||||
@ -24,14 +24,14 @@ class PrivateKey():
|
|||||||
#: private key in bytes (bytes)
|
#: private key in bytes (bytes)
|
||||||
self.key = create_private_key(wif=False)
|
self.key = create_private_key(wif=False)
|
||||||
#: private key in HEX (string)
|
#: private key in HEX (string)
|
||||||
self.hex = hexlify(self.key).decode()
|
self.hex = self.key.hex()
|
||||||
#: private key in WIF format (string)
|
#: private key in WIF format (string)
|
||||||
self.wif = private_key_to_wif(self.key, compressed, testnet)
|
self.wif = private_key_to_wif(self.key, compressed, testnet)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if isinstance(key, str):
|
if isinstance(key, str):
|
||||||
try:
|
try:
|
||||||
key = unhexlify(key)
|
key = bytes.fromhex(key)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if isinstance(key, bytes):
|
if isinstance(key, bytes):
|
||||||
@ -40,14 +40,14 @@ class PrivateKey():
|
|||||||
self.key = key
|
self.key = key
|
||||||
self.compressed = compressed
|
self.compressed = compressed
|
||||||
self.testnet = testnet
|
self.testnet = testnet
|
||||||
self.hex = hexlify(self.key).decode()
|
self.hex = self.key.hex()
|
||||||
self.wif = private_key_to_wif(self.key, compressed, testnet)
|
self.wif = private_key_to_wif(self.key, compressed, testnet)
|
||||||
return
|
return
|
||||||
if not isinstance(key, str) or not is_wif_valid(key):
|
if not isinstance(key, str) or not is_wif_valid(key):
|
||||||
raise TypeError("private key invalid")
|
raise TypeError("private key invalid")
|
||||||
|
|
||||||
self.key = wif_to_private_key(key, hex=False)
|
self.key = wif_to_private_key(key, hex=False)
|
||||||
self.hex = hexlify(self.key).decode()
|
self.hex = self.key.hex()
|
||||||
if key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
|
if key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
|
||||||
TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
|
TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
|
||||||
self.compressed = False
|
self.compressed = False
|
||||||
@ -90,7 +90,7 @@ class PublicKey():
|
|||||||
def __init__(self, key, compressed=True, testnet=False):
|
def __init__(self, key, compressed=True, testnet=False):
|
||||||
if isinstance(key, str):
|
if isinstance(key, str):
|
||||||
try:
|
try:
|
||||||
key = unhexlify(key)
|
key = bytes.fromhex(key)
|
||||||
except:
|
except:
|
||||||
if is_wif_valid(key):
|
if is_wif_valid(key):
|
||||||
key = PrivateKey(key)
|
key = PrivateKey(key)
|
||||||
@ -116,7 +116,7 @@ class PublicKey():
|
|||||||
#: public key in bytes (bytes)
|
#: public key in bytes (bytes)
|
||||||
self.key = public_key
|
self.key = public_key
|
||||||
#: public key in HEX (string)
|
#: public key in HEX (string)
|
||||||
self.hex = hexlify(self.key).decode()
|
self.hex = self.key.hex()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.hex
|
return self.hex
|
||||||
@ -183,7 +183,7 @@ class Address():
|
|||||||
#: redeeem script, only for P2SH_P2WPKH (bytes)
|
#: redeeem script, only for P2SH_P2WPKH (bytes)
|
||||||
self.redeem_script = public_key_to_p2sh_p2wpkh_script(self.public_key.key)
|
self.redeem_script = public_key_to_p2sh_p2wpkh_script(self.public_key.key)
|
||||||
#: redeeem script HEX, only for P2SH_P2WPKH (string)
|
#: redeeem script HEX, only for P2SH_P2WPKH (string)
|
||||||
self.redeem_script_hex = hexlify(self.redeem_script).decode()
|
self.redeem_script_hex = self.redeem_script.hex()
|
||||||
#: address hash
|
#: address hash
|
||||||
self.hash = hash160(self.redeem_script)
|
self.hash = hash160(self.redeem_script)
|
||||||
self.witness_version = None
|
self.witness_version = None
|
||||||
@ -191,7 +191,7 @@ class Address():
|
|||||||
self.script_hash = False
|
self.script_hash = False
|
||||||
self.hash = hash160(self.public_key.key)
|
self.hash = hash160(self.public_key.key)
|
||||||
#: address hash HEX (string)
|
#: address hash HEX (string)
|
||||||
self.hash_hex = hexlify(self.hash).decode()
|
self.hash_hex = self.hash.hex()
|
||||||
#: address in base58 or bech32 encoding (string)
|
#: address in base58 or bech32 encoding (string)
|
||||||
self.address = hash_to_address(self.hash,
|
self.address = hash_to_address(self.hash,
|
||||||
script_hash=self.script_hash,
|
script_hash=self.script_hash,
|
||||||
@ -208,9 +208,9 @@ class ScriptAddress():
|
|||||||
self.witness_version = witness_version
|
self.witness_version = witness_version
|
||||||
self.testnet = testnet
|
self.testnet = testnet
|
||||||
if isinstance(script, str):
|
if isinstance(script, str):
|
||||||
script = unhexlify(script)
|
script = bytes.fromhex(script)
|
||||||
self.script = script
|
self.script = script
|
||||||
self.script_hex = hexlify(self.script).decode()
|
self.script_hex = self.script.hex()
|
||||||
if witness_version is None:
|
if witness_version is None:
|
||||||
self.hash = hash160(self.script)
|
self.hash = hash160(self.script)
|
||||||
else:
|
else:
|
||||||
@ -248,7 +248,7 @@ class ScriptAddress():
|
|||||||
for a in list(public_key_list):
|
for a in list(public_key_list):
|
||||||
if isinstance(a, str):
|
if isinstance(a, str):
|
||||||
try:
|
try:
|
||||||
a = unhexlify(a)
|
a = bytes.fromhex(a)
|
||||||
except:
|
except:
|
||||||
if is_wif_valid(a):
|
if is_wif_valid(a):
|
||||||
a = private_to_public_key(a, hex=False)
|
a = private_to_public_key(a, hex=False)
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
from .tools import *
|
|
||||||
from .transaction import Transaction
|
from .transaction import Transaction
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
from .functions import *
|
||||||
|
|
||||||
class Block(dict):
|
class Block(dict):
|
||||||
def __init__(self, raw_block=None, format="decoded", version=536870912, testnet=False):
|
def __init__(self, raw_block=None, format="decoded", version=536870912, testnet=False):
|
||||||
@ -12,7 +11,7 @@ class Block(dict):
|
|||||||
self["header"] = None
|
self["header"] = None
|
||||||
self["hash"] = None
|
self["hash"] = None
|
||||||
self["version"] = version
|
self["version"] = version
|
||||||
self["versionHex"] = hexlify(struct.pack(">L", version)).decode()
|
self["versionHex"] = struct.pack(">L", version).hex()
|
||||||
self["previousBlockHash"] = None
|
self["previousBlockHash"] = None
|
||||||
self["merkleRoot"] = None
|
self["merkleRoot"] = None
|
||||||
self["tx"] = dict()
|
self["tx"] = dict()
|
||||||
@ -33,7 +32,7 @@ class Block(dict):
|
|||||||
s = self.get_stream(raw_block)
|
s = self.get_stream(raw_block)
|
||||||
self["format"] = "raw"
|
self["format"] = "raw"
|
||||||
self["version"] = unpack("<L", s.read(4))[0]
|
self["version"] = unpack("<L", s.read(4))[0]
|
||||||
self["versionHex"] = hexlify(struct.pack(">L", self["version"])).decode()
|
self["versionHex"] = struct.pack(">L", self["version"]).hex()
|
||||||
self["previousBlockHash"] = s.read(32)
|
self["previousBlockHash"] = s.read(32)
|
||||||
self["merkleRoot"] = s.read(32)
|
self["merkleRoot"] = s.read(32)
|
||||||
self["time"] = unpack("<L", s.read(4))[0]
|
self["time"] = unpack("<L", s.read(4))[0]
|
||||||
@ -75,7 +74,7 @@ class Block(dict):
|
|||||||
if isinstance(self["merkleRoot"], bytes):
|
if isinstance(self["merkleRoot"], bytes):
|
||||||
self["merkleRoot"] = rh2s(self["merkleRoot"])
|
self["merkleRoot"] = rh2s(self["merkleRoot"])
|
||||||
if isinstance(self["header"], bytes):
|
if isinstance(self["header"], bytes):
|
||||||
self["header"] = hexlify(self["header"]).decode()
|
self["header"] = self["header"].hex()
|
||||||
if isinstance(self["bits"], bytes):
|
if isinstance(self["bits"], bytes):
|
||||||
self["bits"] = rh2s(self["bits"])
|
self["bits"] = rh2s(self["bits"])
|
||||||
for i in self["tx"]:
|
for i in self["tx"]:
|
||||||
@ -85,7 +84,7 @@ class Block(dict):
|
|||||||
def get_stream(stream):
|
def get_stream(stream):
|
||||||
if type(stream) != io.BytesIO:
|
if type(stream) != io.BytesIO:
|
||||||
if type(stream) == str:
|
if type(stream) == str:
|
||||||
stream = unhexlify(stream)
|
stream = bytes.fromhex(stream)
|
||||||
if type(stream) == bytes:
|
if type(stream) == bytes:
|
||||||
stream = io.BytesIO(stream)
|
stream = io.BytesIO(stream)
|
||||||
else:
|
else:
|
||||||
|
|||||||
7
pybtc/functions/__init__.py
Normal file
7
pybtc/functions/__init__.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from .key import *
|
||||||
|
from .address import *
|
||||||
|
from .script import *
|
||||||
|
from .tools import *
|
||||||
|
from .hash import *
|
||||||
|
from .block import *
|
||||||
|
from .encode import *
|
||||||
286
pybtc/functions/address.py
Normal file
286
pybtc/functions/address.py
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
from secp256k1 import ffi
|
||||||
|
parentPath = os.path.abspath("../..")
|
||||||
|
if parentPath not in sys.path:
|
||||||
|
sys.path.insert(0, parentPath)
|
||||||
|
|
||||||
|
from pybtc.constants import *
|
||||||
|
from .hash import *
|
||||||
|
from pybtc.opcodes import *
|
||||||
|
from .encode import *
|
||||||
|
from .key import *
|
||||||
|
from .hash import *
|
||||||
|
|
||||||
|
|
||||||
|
def hash_to_address(address_hash, testnet=False, script_hash=False, witness_version=0):
|
||||||
|
"""
|
||||||
|
Get address from public key/script hash. In case PUBKEY, P2PKH, P2PKH public key/script hash is SHA256+RIPEMD160,
|
||||||
|
P2WSH script hash is SHA256.
|
||||||
|
|
||||||
|
|
||||||
|
:param address_hash: public key hash or script hash in HEX or bytes string format.
|
||||||
|
:param testnet: (optional) flag for testnet network, by default is False.
|
||||||
|
:param script_hash: (optional) flag for script hash (P2SH address), by default is False.
|
||||||
|
:param witness_version: (optional) witness program version, by default is 0, for legacy
|
||||||
|
address format use None.
|
||||||
|
:return: address in base58 or bech32 format.
|
||||||
|
"""
|
||||||
|
if isinstance(address_hash, str):
|
||||||
|
address_hash = bytes.fromhex(address_hash)
|
||||||
|
if not isinstance(address_hash, bytes):
|
||||||
|
raise TypeError("address hash must be HEX encoded string or bytes")
|
||||||
|
|
||||||
|
if not script_hash:
|
||||||
|
if witness_version is None:
|
||||||
|
if len(address_hash) != 20:
|
||||||
|
raise ValueError("address hash length incorrect")
|
||||||
|
if testnet:
|
||||||
|
prefix = TESTNET_ADDRESS_BYTE_PREFIX
|
||||||
|
else:
|
||||||
|
prefix = MAINNET_ADDRESS_BYTE_PREFIX
|
||||||
|
address_hash = prefix + address_hash
|
||||||
|
address_hash += double_sha256(address_hash)[:4]
|
||||||
|
return encode_base58(address_hash)
|
||||||
|
else:
|
||||||
|
if len(address_hash) not in (20, 32):
|
||||||
|
raise ValueError("address hash length incorrect")
|
||||||
|
|
||||||
|
if witness_version is None:
|
||||||
|
if testnet:
|
||||||
|
prefix = TESTNET_SCRIPT_ADDRESS_BYTE_PREFIX
|
||||||
|
else:
|
||||||
|
prefix = MAINNET_SCRIPT_ADDRESS_BYTE_PREFIX
|
||||||
|
address_hash = prefix + address_hash
|
||||||
|
address_hash += double_sha256(address_hash)[:4]
|
||||||
|
return encode_base58(address_hash)
|
||||||
|
|
||||||
|
if testnet:
|
||||||
|
prefix = TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX
|
||||||
|
hrp = TESTNET_SEGWIT_ADDRESS_PREFIX
|
||||||
|
else:
|
||||||
|
prefix = MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX
|
||||||
|
hrp = MAINNET_SEGWIT_ADDRESS_PREFIX
|
||||||
|
|
||||||
|
address_hash = b"%s%s" % (witness_version.to_bytes(1, "big"),
|
||||||
|
rebase_8_to_5(address_hash))
|
||||||
|
checksum = bech32_polymod(b"%s%s%s" % (prefix, address_hash, b"\x00" * 6))
|
||||||
|
checksum = rebase_8_to_5(checksum.to_bytes(5, "big"))[2:]
|
||||||
|
return "%s1%s" % (hrp, rebase_5_to_32(address_hash + checksum).decode())
|
||||||
|
|
||||||
|
|
||||||
|
def public_key_to_address(pubkey, testnet=False, p2sh_p2wpkh=False, witness_version=0):
|
||||||
|
"""
|
||||||
|
Get address from public key/script hash. In case PUBKEY, P2PKH, P2PKH public key/script hash is SHA256+RIPEMD160,
|
||||||
|
P2WSH script hash is SHA256.
|
||||||
|
|
||||||
|
:param pubkey: public key HEX or bytes string format.
|
||||||
|
:param testnet: (optional) flag for testnet network, by default is False.
|
||||||
|
:param p2sh_p2wpkh: (optional) flag for P2WPKH inside P2SH address, by default is False.
|
||||||
|
:param witness_version: (optional) witness program version, by default is 0, for legacy
|
||||||
|
address format use None.
|
||||||
|
:return: address in base58 or bech32 format.
|
||||||
|
"""
|
||||||
|
if isinstance(pubkey, str):
|
||||||
|
pubkey = bytes.fromhex(pubkey)
|
||||||
|
if not isinstance(pubkey, bytes):
|
||||||
|
raise TypeError("public key invalid, expected bytes or str")
|
||||||
|
if p2sh_p2wpkh:
|
||||||
|
if len(pubkey) != 33:
|
||||||
|
raise ValueError("public key invalid")
|
||||||
|
h = hash160(b'\x00\x14%s' % hash160(pubkey))
|
||||||
|
witness_version = None
|
||||||
|
else:
|
||||||
|
if witness_version is not None:
|
||||||
|
if len(pubkey) != 33:
|
||||||
|
raise ValueError("public key invalid")
|
||||||
|
h = hash160(pubkey)
|
||||||
|
return hash_to_address(h, testnet=testnet,
|
||||||
|
script_hash=p2sh_p2wpkh,
|
||||||
|
witness_version=witness_version)
|
||||||
|
|
||||||
|
|
||||||
|
def address_to_hash(address, hex=True):
|
||||||
|
"""
|
||||||
|
Get address hash from base58 or bech32 address format.
|
||||||
|
|
||||||
|
:param address: address in base58 or bech32 format.
|
||||||
|
:param hex: (optional) If set to True return key in HEX format, by default is True.
|
||||||
|
:return: script in HEX or bytes string.
|
||||||
|
"""
|
||||||
|
if address[0] in ADDRESS_PREFIX_LIST:
|
||||||
|
h = decode_base58(address)[1:-4]
|
||||||
|
elif address[:2] in (MAINNET_SEGWIT_ADDRESS_PREFIX,
|
||||||
|
TESTNET_SEGWIT_ADDRESS_PREFIX):
|
||||||
|
address = address.split("1")[1]
|
||||||
|
h = rebase_5_to_8(rebase_32_to_5(address)[1:-6], False)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
return h.hex() if hex else h
|
||||||
|
|
||||||
|
|
||||||
|
def address_type(address, num=False):
|
||||||
|
"""
|
||||||
|
Get address type.
|
||||||
|
|
||||||
|
:param address: address in base58 or bech32 format.
|
||||||
|
:param num: (optional) If set to True return type in numeric format, by default is False.
|
||||||
|
:return: address type in string or numeric format.
|
||||||
|
"""
|
||||||
|
if address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX,
|
||||||
|
MAINNET_SCRIPT_ADDRESS_PREFIX):
|
||||||
|
t = 'P2SH'
|
||||||
|
elif address[0] in (MAINNET_ADDRESS_PREFIX,
|
||||||
|
TESTNET_ADDRESS_PREFIX,
|
||||||
|
TESTNET_ADDRESS_PREFIX_2):
|
||||||
|
t = 'P2PKH'
|
||||||
|
elif address[:2] in (MAINNET_SEGWIT_ADDRESS_PREFIX,
|
||||||
|
TESTNET_SEGWIT_ADDRESS_PREFIX):
|
||||||
|
if len(address) == 42:
|
||||||
|
t = 'P2WPKH'
|
||||||
|
elif len(address) == 62:
|
||||||
|
t = 'P2WSH'
|
||||||
|
else:
|
||||||
|
return SCRIPT_TYPES['NON_STANDARD'] if num else 'UNKNOWN'
|
||||||
|
else:
|
||||||
|
return SCRIPT_TYPES['NON_STANDARD'] if num else 'UNKNOWN'
|
||||||
|
return SCRIPT_TYPES[t] if num else t
|
||||||
|
|
||||||
|
|
||||||
|
def address_net_type(address):
|
||||||
|
"""
|
||||||
|
Get address network type.
|
||||||
|
|
||||||
|
:param address: address in base58 or bech32 format.
|
||||||
|
:return: address network type in string format or None.
|
||||||
|
"""
|
||||||
|
if address[0] in (MAINNET_SCRIPT_ADDRESS_PREFIX,
|
||||||
|
MAINNET_ADDRESS_PREFIX):
|
||||||
|
return "mainnet"
|
||||||
|
elif address[:2] == MAINNET_SEGWIT_ADDRESS_PREFIX:
|
||||||
|
return "mainnet"
|
||||||
|
elif address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX,
|
||||||
|
TESTNET_ADDRESS_PREFIX,
|
||||||
|
TESTNET_ADDRESS_PREFIX_2):
|
||||||
|
return "testnet"
|
||||||
|
elif address[:2] == TESTNET_SEGWIT_ADDRESS_PREFIX:
|
||||||
|
return "testnet"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def address_to_script(address, hex=False):
|
||||||
|
"""
|
||||||
|
Get public key script from address.
|
||||||
|
|
||||||
|
:param address: address in base58 or bech32 format.
|
||||||
|
:param hex: (optional) If set to True return key in HEX format, by default is True.
|
||||||
|
:return: public key script in HEX or bytes string.
|
||||||
|
"""
|
||||||
|
if address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX,
|
||||||
|
MAINNET_SCRIPT_ADDRESS_PREFIX):
|
||||||
|
s = [OP_HASH160,
|
||||||
|
b'\x14',
|
||||||
|
address_to_hash(address, hex=False),
|
||||||
|
OP_EQUAL]
|
||||||
|
elif address[0] in (MAINNET_ADDRESS_PREFIX,
|
||||||
|
TESTNET_ADDRESS_PREFIX,
|
||||||
|
TESTNET_ADDRESS_PREFIX_2):
|
||||||
|
s = [OP_DUP,
|
||||||
|
OP_HASH160,
|
||||||
|
b'\x14',
|
||||||
|
address_to_hash(address, hex=False),
|
||||||
|
OP_EQUALVERIFY,
|
||||||
|
OP_CHECKSIG]
|
||||||
|
elif address[:2] in (TESTNET_SEGWIT_ADDRESS_PREFIX,
|
||||||
|
MAINNET_SEGWIT_ADDRESS_PREFIX):
|
||||||
|
h = address_to_hash(address, hex=False)
|
||||||
|
s = [OP_0,
|
||||||
|
bytes([len(h)]),
|
||||||
|
h]
|
||||||
|
else:
|
||||||
|
raise ValueError("address invalid")
|
||||||
|
s = b''.join(s)
|
||||||
|
return s.hex() if hex else s
|
||||||
|
|
||||||
|
|
||||||
|
def public_key_to_p2sh_p2wpkh_script(pubkey):
|
||||||
|
if len(pubkey) != 33:
|
||||||
|
raise ValueError("public key len invalid")
|
||||||
|
return b'\x00\x14%s' % hash160(pubkey)
|
||||||
|
|
||||||
|
|
||||||
|
def is_address_valid(address, testnet=False):
|
||||||
|
"""
|
||||||
|
Check is address valid.
|
||||||
|
|
||||||
|
:param address: address in base58 or bech32 format.
|
||||||
|
:param testnet: (optional) flag for testnet network, by default is False.
|
||||||
|
:return: boolean.
|
||||||
|
"""
|
||||||
|
if not address or type(address) != str:
|
||||||
|
return False
|
||||||
|
if address[0] in (MAINNET_ADDRESS_PREFIX,
|
||||||
|
MAINNET_SCRIPT_ADDRESS_PREFIX,
|
||||||
|
TESTNET_ADDRESS_PREFIX,
|
||||||
|
TESTNET_ADDRESS_PREFIX_2,
|
||||||
|
TESTNET_SCRIPT_ADDRESS_PREFIX):
|
||||||
|
if testnet:
|
||||||
|
if address[0] not in (TESTNET_ADDRESS_PREFIX,
|
||||||
|
TESTNET_ADDRESS_PREFIX_2,
|
||||||
|
TESTNET_SCRIPT_ADDRESS_PREFIX):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if address[0] not in (MAINNET_ADDRESS_PREFIX,
|
||||||
|
MAINNET_SCRIPT_ADDRESS_PREFIX):
|
||||||
|
return False
|
||||||
|
h = decode_base58(address)
|
||||||
|
if len(h) != 25:
|
||||||
|
return False
|
||||||
|
checksum = h[-4:]
|
||||||
|
if double_sha256(h[:-4])[:4] != checksum:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
elif address[:2].lower() in (TESTNET_SEGWIT_ADDRESS_PREFIX,
|
||||||
|
MAINNET_SEGWIT_ADDRESS_PREFIX):
|
||||||
|
if len(address) not in (42, 62):
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
prefix, payload = address.split('1')
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
upp = True if prefix[0].isupper() else False
|
||||||
|
for i in payload[1:]:
|
||||||
|
if upp:
|
||||||
|
if not i.isupper() or i not in base32charset_upcase:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if i.isupper() or i not in base32charset:
|
||||||
|
return False
|
||||||
|
payload = payload.lower()
|
||||||
|
prefix = prefix.lower()
|
||||||
|
if testnet:
|
||||||
|
if prefix != TESTNET_SEGWIT_ADDRESS_PREFIX:
|
||||||
|
return False
|
||||||
|
stripped_prefix = TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX
|
||||||
|
else:
|
||||||
|
if prefix != MAINNET_SEGWIT_ADDRESS_PREFIX:
|
||||||
|
return False
|
||||||
|
stripped_prefix = MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX
|
||||||
|
d = rebase_32_to_5(payload)
|
||||||
|
address_hash = d[:-6]
|
||||||
|
checksum = d[-6:]
|
||||||
|
checksum2 = bech32_polymod(stripped_prefix + address_hash + b"\x00" * 6)
|
||||||
|
checksum2 = rebase_8_to_5(checksum2.to_bytes(5, "big"))[2:]
|
||||||
|
if checksum != checksum2:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_witness_version(address):
|
||||||
|
address = address.split("1")[1]
|
||||||
|
h = rebase_32_to_5(address)
|
||||||
|
return h[0]
|
||||||
|
|
||||||
|
|
||||||
125
pybtc/functions/block.py
Normal file
125
pybtc/functions/block.py
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
|
||||||
|
def merkle_root(tx_hash_list, hex=True):
|
||||||
|
"""
|
||||||
|
Calculate merkle root from transaction hash list
|
||||||
|
|
||||||
|
:param tx_hash_list: list of transaction hashes in bytes or HEX encoded string.
|
||||||
|
: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.
|
||||||
|
"""
|
||||||
|
tx_hash_list = [h if isinstance(h, bytes) else s2rh(h) for h in tx_hash_list]
|
||||||
|
if len(tx_hash_list) == 1:
|
||||||
|
return tx_hash_list[0]
|
||||||
|
while True:
|
||||||
|
new_hash_list = list()
|
||||||
|
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))
|
||||||
|
if len(new_hash_list) > 1:
|
||||||
|
tx_hash_list = new_hash_list
|
||||||
|
else:
|
||||||
|
return new_hash_list[0] if not hex else hexlify(new_hash_list[0]).decode()
|
||||||
|
|
||||||
|
|
||||||
|
def merkle_branches(tx_hash_list, hex=True):
|
||||||
|
"""
|
||||||
|
Calculate merkle branches for coinbase transacton
|
||||||
|
|
||||||
|
:param tx_hash_list: list of transaction hashes in bytes or HEX encoded string.
|
||||||
|
:param hex: (optional) If set to True return result in HEX format, by default is True.
|
||||||
|
:return: list of merkle branches in bytes or HEX encoded string corresponding hex flag.
|
||||||
|
"""
|
||||||
|
tx_hash_list = [h if isinstance(h, bytes) else s2rh(h) for h in tx_hash_list]
|
||||||
|
branches = []
|
||||||
|
if len(tx_hash_list) == 1:
|
||||||
|
return []
|
||||||
|
tx_hash_list.pop(0)
|
||||||
|
while True:
|
||||||
|
branches.append(tx_hash_list.pop(0))
|
||||||
|
new_hash_list = list()
|
||||||
|
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))
|
||||||
|
if len(new_hash_list) > 1:
|
||||||
|
tx_hash_list = new_hash_list
|
||||||
|
else:
|
||||||
|
if new_hash_list:
|
||||||
|
branches.append(new_hash_list.pop(0))
|
||||||
|
return branches if not hex else [hexlify(h).decode() for h in branches]
|
||||||
|
|
||||||
|
|
||||||
|
def merkleroot_from_branches(merkle_branches, coinbase_hash, hex=True):
|
||||||
|
"""
|
||||||
|
Calculate merkle root from merkle branches and coinbase transacton hash
|
||||||
|
|
||||||
|
:param merkle_branches: list merkle branches in bytes or HEX encoded string.
|
||||||
|
:param coinbase_hash: list coinbase transaction hash in bytes or HEX encoded string.
|
||||||
|
: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 unhexlify(coinbase_hash)
|
||||||
|
for h in merkle_branches:
|
||||||
|
if type(h) == str:
|
||||||
|
h = unhexlify(h)
|
||||||
|
merkle_root = double_sha256(merkle_root + h)
|
||||||
|
return merkle_root if not hex else hexlify(merkle_root).decode()
|
||||||
|
|
||||||
|
|
||||||
|
# Difficulty
|
||||||
|
|
||||||
|
|
||||||
|
def bits_to_target(bits):
|
||||||
|
"""
|
||||||
|
Calculate target from bits
|
||||||
|
|
||||||
|
:param bits: HEX string, bytes string or integer representation of bits.
|
||||||
|
:return: integer.
|
||||||
|
"""
|
||||||
|
if type(bits) == str:
|
||||||
|
bits = unhexlify(bits)
|
||||||
|
if type(bits) == bytes:
|
||||||
|
return int.from_bytes(bits[1:], 'big') * (2 ** (8 * (bits[0] - 3)))
|
||||||
|
else:
|
||||||
|
shift = bits >> 24
|
||||||
|
target = (bits & 0xffffff) * (1 << (8 * (shift - 3)))
|
||||||
|
return target
|
||||||
|
|
||||||
|
|
||||||
|
def target_to_difficulty(target):
|
||||||
|
"""
|
||||||
|
Calculate difficulty from target
|
||||||
|
|
||||||
|
:param target: integer.
|
||||||
|
:return: float.
|
||||||
|
"""
|
||||||
|
return 0x00000000FFFF0000000000000000000000000000000000000000000000000000 / target
|
||||||
|
|
||||||
|
|
||||||
|
def bits_to_difficulty(bits):
|
||||||
|
"""
|
||||||
|
Calculate difficulty from bits
|
||||||
|
|
||||||
|
:param bits: HEX string, bytes string or integer representation of bits.
|
||||||
|
:return: integer.
|
||||||
|
"""
|
||||||
|
return target_to_difficulty(bits_to_target(bits))
|
||||||
|
|
||||||
|
|
||||||
|
def difficulty_to_target(difficulty):
|
||||||
|
"""
|
||||||
|
Calculate target from difficulty
|
||||||
|
|
||||||
|
:param target: integer.
|
||||||
|
:return: float.
|
||||||
|
"""
|
||||||
|
return int(0x00000000FFFF0000000000000000000000000000000000000000000000000000 / difficulty)
|
||||||
|
|
||||||
|
|
||||||
@ -1,5 +1,3 @@
|
|||||||
from binascii import hexlify, unhexlify
|
|
||||||
|
|
||||||
b58_digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
b58_digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||||||
base32charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
|
base32charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
|
||||||
base32charset_upcase = "QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L"
|
base32charset_upcase = "QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L"
|
||||||
@ -23,7 +21,7 @@ def rebasebits(data, frombits, tobits, pad=True):
|
|||||||
max_acc = (1 << (frombits + tobits - 1)) - 1
|
max_acc = (1 << (frombits + tobits - 1)) - 1
|
||||||
for value in data:
|
for value in data:
|
||||||
if value < 0 or (value >> frombits):
|
if value < 0 or (value >> frombits):
|
||||||
raise Exception("invalid bytes")
|
raise ValueError("invalid bytes")
|
||||||
acc = ((acc << frombits) | value) & max_acc
|
acc = ((acc << frombits) | value) & max_acc
|
||||||
bits += frombits
|
bits += frombits
|
||||||
while bits >= tobits:
|
while bits >= tobits:
|
||||||
@ -33,7 +31,7 @@ def rebasebits(data, frombits, tobits, pad=True):
|
|||||||
if bits:
|
if bits:
|
||||||
ret.append((acc << (tobits - bits)) & maxv)
|
ret.append((acc << (tobits - bits)) & maxv)
|
||||||
elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
|
elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
|
||||||
raise Exception("invalid padding")
|
raise ValueError("invalid padding")
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
@ -79,7 +77,9 @@ def bech32_polymod(values):
|
|||||||
def encode_base58(b):
|
def encode_base58(b):
|
||||||
"""Encode bytes to a base58-encoded string"""
|
"""Encode bytes to a base58-encoded string"""
|
||||||
# Convert big-endian bytes to integer
|
# Convert big-endian bytes to integer
|
||||||
n = int('0x0' + hexlify(b).decode('utf8'), 16)
|
|
||||||
|
n= int('0x0' + b.hex(), 16)
|
||||||
|
|
||||||
# Divide that integer into bas58
|
# Divide that integer into bas58
|
||||||
res = []
|
res = []
|
||||||
while n > 0:
|
while n > 0:
|
||||||
@ -113,7 +113,7 @@ def decode_base58(s):
|
|||||||
h = '%x' % n
|
h = '%x' % n
|
||||||
if len(h) % 2:
|
if len(h) % 2:
|
||||||
h = '0' + h
|
h = '0' + h
|
||||||
res = unhexlify(h.encode('utf8'))
|
res = bytes.fromhex(h)
|
||||||
# Add padding back.
|
# Add padding back.
|
||||||
pad = 0
|
pad = 0
|
||||||
for c in s[:-1]:
|
for c in s[:-1]:
|
||||||
@ -1,42 +1,43 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
from binascii import unhexlify
|
|
||||||
|
|
||||||
def sha256(h, hex = False):
|
|
||||||
|
def sha256(h, hex=False):
|
||||||
if type(h) == str:
|
if type(h) == str:
|
||||||
h = unhexlify(h)
|
h = bytes.fromhex(h)
|
||||||
if hex:
|
if hex:
|
||||||
return hashlib.sha256(h).hexdigest()
|
return hashlib.sha256(h).hexdigest()
|
||||||
return hashlib.sha256(h).digest()
|
return hashlib.sha256(h).digest()
|
||||||
|
|
||||||
def double_sha256(h, hex = False):
|
|
||||||
|
def double_sha256(h, hex=False):
|
||||||
if type(h) == str:
|
if type(h) == str:
|
||||||
h = unhexlify(h)
|
h = bytes.fromhex(h)
|
||||||
if hex:
|
if hex:
|
||||||
return sha256(sha256(h), 1)
|
return sha256(sha256(h), 1)
|
||||||
return sha256(sha256(h))
|
return sha256(sha256(h))
|
||||||
|
|
||||||
def hmac_sha512(key, data, hex = False):
|
|
||||||
|
def hmac_sha512(key, data, hex=False):
|
||||||
if hex:
|
if hex:
|
||||||
return hmac.new(key, data, hashlib.sha512).hexdigest()
|
return hmac.new(key, data, hashlib.sha512).hexdigest()
|
||||||
return hmac.new(key, data, hashlib.sha512).digest()
|
return hmac.new(key, data, hashlib.sha512).digest()
|
||||||
|
|
||||||
|
|
||||||
def ripemd160(h, hex = False):
|
def ripemd160(h, hex=False):
|
||||||
if type(h) == str:
|
if type(h) == str:
|
||||||
h = unhexlify(h)
|
h = bytes.fromhex(h)
|
||||||
a = hashlib.new('ripemd160')
|
a = hashlib.new('ripemd160')
|
||||||
a.update(h)
|
a.update(h)
|
||||||
if hex:
|
if hex:
|
||||||
return a.hexdigest()
|
return a.hexdigest()
|
||||||
return a.digest()
|
return a.digest()
|
||||||
|
|
||||||
def hash160(h, hex = False):
|
|
||||||
|
def hash160(h, hex=False):
|
||||||
if type(h) == str:
|
if type(h) == str:
|
||||||
h = unhexlify(h)
|
bytes.fromhex(h)
|
||||||
if hex:
|
if hex:
|
||||||
return ripemd160(sha256(h), 1)
|
return ripemd160(sha256(h), 1)
|
||||||
return ripemd160(sha256(h))
|
return ripemd160(sha256(h))
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
168
pybtc/functions/key.py
Normal file
168
pybtc/functions/key.py
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
from secp256k1 import ffi
|
||||||
|
parentPath = os.path.abspath("../..")
|
||||||
|
if parentPath not in sys.path:
|
||||||
|
sys.path.insert(0, parentPath)
|
||||||
|
|
||||||
|
from pybtc.constants import *
|
||||||
|
from .hash import *
|
||||||
|
from .encode import *
|
||||||
|
from .hash import *
|
||||||
|
|
||||||
|
|
||||||
|
def create_private_key(compressed=True, testnet=False, wif=True, hex=False):
|
||||||
|
"""
|
||||||
|
Create private key
|
||||||
|
|
||||||
|
:param compressed: (optional) Type of public key, by default set to compressed.
|
||||||
|
Using uncompressed public keys is deprecated in new SEGWIT addresses,
|
||||||
|
use this option only for backward compatibility.
|
||||||
|
:param testnet: (optional) flag for testnet network, by default is False.
|
||||||
|
:param wif: (optional) If set to True return key in WIF format, by default is True.
|
||||||
|
:param hex: (optional) If set to True return key in HEX format, by default is False.
|
||||||
|
:return: Private key in wif format (default), hex encoded byte string in case of hex flag or
|
||||||
|
raw bytes string in case wif and hex flags set to False.
|
||||||
|
|
||||||
|
"""
|
||||||
|
a = random.SystemRandom().randint(0, MAX_INT_PRIVATE_KEY)
|
||||||
|
i = int((time.time() % 0.01 ) * 100000)
|
||||||
|
h = a.to_bytes(32, byteorder="big")
|
||||||
|
# more entropy from system timer and sha256 derivation
|
||||||
|
while i:
|
||||||
|
h = hashlib.sha256(h).digest()
|
||||||
|
i -= 1
|
||||||
|
if not i and int.from_bytes(h, byteorder="big") > MAX_INT_PRIVATE_KEY:
|
||||||
|
i += 1
|
||||||
|
if wif:
|
||||||
|
return private_key_to_wif(h, compressed=compressed, testnet=testnet)
|
||||||
|
elif hex:
|
||||||
|
return h.hex()
|
||||||
|
return h
|
||||||
|
|
||||||
|
|
||||||
|
def private_key_to_wif(h, compressed=True, testnet=False):
|
||||||
|
"""
|
||||||
|
Encode private key in HEX or RAW bytes format to WIF format.
|
||||||
|
|
||||||
|
:param h: private key 32 byte string or HEX encoded string.
|
||||||
|
:param compressed: (optional) flag of public key compressed format, by default set to True.
|
||||||
|
:param testnet: (optional) flag for testnet network, by default is False.
|
||||||
|
:return: Private key in WIF format.
|
||||||
|
"""
|
||||||
|
# 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)
|
||||||
|
if len(h) != 32 and isinstance(h, bytes):
|
||||||
|
raise TypeError("private key must be a 32 bytes or hex encoded string")
|
||||||
|
if testnet:
|
||||||
|
h = TESTNET_PRIVATE_KEY_BYTE_PREFIX + h
|
||||||
|
else:
|
||||||
|
h = MAINNET_PRIVATE_KEY_BYTE_PREFIX + h
|
||||||
|
if compressed:
|
||||||
|
h += b'\x01'
|
||||||
|
h += double_sha256(h)[:4]
|
||||||
|
return encode_base58(h)
|
||||||
|
|
||||||
|
|
||||||
|
def wif_to_private_key(h, hex=True):
|
||||||
|
"""
|
||||||
|
Decode WIF private key to bytes string or HEX encoded string
|
||||||
|
|
||||||
|
:param hex: (optional) if set to True return key in HEX format, by default is True.
|
||||||
|
:return: Private key HEX encoded string or raw bytes string.
|
||||||
|
"""
|
||||||
|
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]
|
||||||
|
|
||||||
|
|
||||||
|
def is_wif_valid(wif):
|
||||||
|
"""
|
||||||
|
Check is private key in WIF format string is valid.
|
||||||
|
|
||||||
|
:param wif: private key in WIF format string.
|
||||||
|
:return: boolean.
|
||||||
|
"""
|
||||||
|
if not isinstance(wif, str):
|
||||||
|
raise TypeError("invalid wif key")
|
||||||
|
if wif[0] not in PRIVATE_KEY_PREFIX_LIST:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
h = decode_base58(wif)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
checksum = h[-4:]
|
||||||
|
if wif[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
|
||||||
|
TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
|
||||||
|
if len(h) != 37:
|
||||||
|
return False
|
||||||
|
elif len(h) != 38:
|
||||||
|
return False
|
||||||
|
if double_sha256(h[:-4])[:4] != checksum:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def private_to_public_key(private_key, compressed=True, hex=True):
|
||||||
|
"""
|
||||||
|
Get public key from private key using ECDSA secp256k1
|
||||||
|
|
||||||
|
:param private_key: private key in WIF, HEX or bytes.
|
||||||
|
:param compressed: (optional) flag of public key compressed format, by default set to True.
|
||||||
|
In case private_key in WIF format, this flag is set in accordance with
|
||||||
|
the key format specified in WIF string.
|
||||||
|
:param hex: (optional) if set to True return key in HEX format, by default is True.
|
||||||
|
:return: 33/65 bytes public key in HEX or bytes string.
|
||||||
|
"""
|
||||||
|
if not isinstance(private_key, bytes):
|
||||||
|
if isinstance(private_key, bytearray):
|
||||||
|
private_key = bytes(private_key)
|
||||||
|
elif isinstance(private_key, str):
|
||||||
|
if not is_wif_valid(private_key):
|
||||||
|
private_key = bytes.fromhex(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)
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
pub = bytes(ffi.buffer(pubkey, len_key))
|
||||||
|
if not r:
|
||||||
|
raise RuntimeError("secp256k1 error")
|
||||||
|
return pub.hex() if hex else pub
|
||||||
|
|
||||||
|
|
||||||
|
def is_public_key_valid(key):
|
||||||
|
"""
|
||||||
|
Check public key is valid.
|
||||||
|
|
||||||
|
:param key: public key in HEX or bytes string format.
|
||||||
|
:return: boolean.
|
||||||
|
"""
|
||||||
|
if isinstance(key, str):
|
||||||
|
key = bytes.fromhex(key)
|
||||||
|
if len(key) < 33:
|
||||||
|
return False
|
||||||
|
elif key[0] == 0x04 and len(key) != 65:
|
||||||
|
return False
|
||||||
|
elif key[0] == 0x02 or key[0] == 0x03:
|
||||||
|
if len(key) != 33:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
0
pybtc/functions/mnemonic.py
Normal file
0
pybtc/functions/mnemonic.py
Normal file
518
pybtc/functions/script.py
Normal file
518
pybtc/functions/script.py
Normal file
@ -0,0 +1,518 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
import struct
|
||||||
|
from secp256k1 import ffi
|
||||||
|
parentPath = os.path.abspath("../..")
|
||||||
|
if parentPath not in sys.path:
|
||||||
|
sys.path.insert(0, parentPath)
|
||||||
|
|
||||||
|
from pybtc.opcodes import *
|
||||||
|
from pybtc.constants import *
|
||||||
|
from .hash import *
|
||||||
|
from .encode import *
|
||||||
|
from .tools import *
|
||||||
|
from .hash import *
|
||||||
|
|
||||||
|
|
||||||
|
def public_key_to_pubkey_script(key, hex=True):
|
||||||
|
if isinstance(key, str):
|
||||||
|
key = bytes.from_hex(key)
|
||||||
|
s = b"%s%s%s" % (bytes([len(key)]), key, OP_CHECKSIG)
|
||||||
|
return s.hex() if hex else s
|
||||||
|
|
||||||
|
|
||||||
|
def parse_script(script, segwit=True):
|
||||||
|
"""
|
||||||
|
Parse script and return script type, script address and required signatures count.
|
||||||
|
|
||||||
|
:param script: script in bytes string or HEX encoded string format.
|
||||||
|
:param segwit: (optional) If set to True recognize P2WPKH and P2WSH sripts, by default set to True.
|
||||||
|
|
||||||
|
:return: dictionary:
|
||||||
|
|
||||||
|
- nType - numeric script type
|
||||||
|
- type - script type
|
||||||
|
- addressHash - address hash in case address recognized
|
||||||
|
- script - script if no address recognized
|
||||||
|
- reqSigs - required signatures count
|
||||||
|
"""
|
||||||
|
if not script:
|
||||||
|
return {"nType": 7, "type": "NON_STANDARD", "reqSigs": 0, "script": b""}
|
||||||
|
if isinstance(script, str):
|
||||||
|
try:
|
||||||
|
script = bytes.fromhex(script)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
assert isinstance(script, bytes)
|
||||||
|
l = len(script)
|
||||||
|
if segwit:
|
||||||
|
if l == 22 and script[0] == 0:
|
||||||
|
return {"nType": 5, "type": "P2WPKH", "reqSigs": 1, "addressHash": script[2:]}
|
||||||
|
if l == 34 and script[0] == 0:
|
||||||
|
return {"nType": 6, "type": "P2WSH", "reqSigs": None, "addressHash": script[2:]}
|
||||||
|
if l == 25 and \
|
||||||
|
script[:2] == b"\x76\xa9" and \
|
||||||
|
script[-2:] == b"\x88\xac":
|
||||||
|
return {"nType": 0, "type": "P2PKH", "reqSigs": 1, "addressHash": script[3:-2]}
|
||||||
|
if l == 23 and \
|
||||||
|
script[0] == 169 and \
|
||||||
|
script[-1] == 135:
|
||||||
|
return {"nType": 1, "type": "P2SH", "reqSigs": None, "addressHash": script[2:-1]}
|
||||||
|
if l == 67 and script[-1] == 172:
|
||||||
|
return {"nType": 2, "type": "PUBKEY", "reqSigs": 1, "addressHash": hash160(script[1:-1])}
|
||||||
|
if l == 35 and script[-1] == 172:
|
||||||
|
return {"nType": 2, "type": "PUBKEY", "reqSigs": 1, "addressHash": hash160(script[1:-1])}
|
||||||
|
if script[0] == 106 and l > 1 and l <= 82:
|
||||||
|
if script[1] == l - 2:
|
||||||
|
return {"nType": 3, "type": "NULL_DATA", "reqSigs": 0, "data": script[2:]}
|
||||||
|
if script[0] >= 81 and script[0] <= 96:
|
||||||
|
if script[-1] == 174:
|
||||||
|
if script[-2] >= 81 and script[-2] <= 96:
|
||||||
|
if script[-2] >= script[0]:
|
||||||
|
c, s = 0, 1
|
||||||
|
while l - 2 - s > 0:
|
||||||
|
if script[s] < 0x4c:
|
||||||
|
s += script[s]
|
||||||
|
c += 1
|
||||||
|
else:
|
||||||
|
c = 0
|
||||||
|
break
|
||||||
|
s += 1
|
||||||
|
if c == script[-2] - 80:
|
||||||
|
return {"nType": 4, "type": "MULTISIG", "reqSigs": script[0] - 80, "script": script}
|
||||||
|
|
||||||
|
s, m, n, last, req_sigs = 0, 0, 0, 0, 0
|
||||||
|
while l - s > 0:
|
||||||
|
if script[s] >= 81 and script[s] <= 96:
|
||||||
|
if not n:
|
||||||
|
n = script[s] - 80
|
||||||
|
else:
|
||||||
|
if m == 0:
|
||||||
|
n, m = script[s] - 80, 0
|
||||||
|
elif n > m:
|
||||||
|
n, m = script[s] - 80, 0
|
||||||
|
elif m == script[s] - 80:
|
||||||
|
last = 0 if last else 2
|
||||||
|
elif script[s] < 0x4c:
|
||||||
|
s += script[s]
|
||||||
|
m += 1
|
||||||
|
if m > 16:
|
||||||
|
n, m = 0, 0
|
||||||
|
elif script[s] == OPCODE["OP_PUSHDATA1"]:
|
||||||
|
try:
|
||||||
|
s += 1 + script[s + 1]
|
||||||
|
except:
|
||||||
|
break
|
||||||
|
elif script[s] == OPCODE["OP_PUSHDATA2"]:
|
||||||
|
try:
|
||||||
|
s += 2 + struct.unpack('<H', script[s: s + 2])[0]
|
||||||
|
except:
|
||||||
|
break
|
||||||
|
elif script[s] == OPCODE["OP_PUSHDATA4"]:
|
||||||
|
try:
|
||||||
|
s += 4 + struct.unpack('<L', script[s: s + 4])[0]
|
||||||
|
except:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if script[s] == OPCODE["OP_CHECKSIG"]:
|
||||||
|
req_sigs += 1
|
||||||
|
elif script[s] == OPCODE["OP_CHECKSIGVERIFY"]:
|
||||||
|
req_sigs += 1
|
||||||
|
elif script[s] in (OPCODE["OP_CHECKMULTISIG"], OPCODE["OP_CHECKMULTISIGVERIFY"]):
|
||||||
|
if last:
|
||||||
|
req_sigs += n
|
||||||
|
else:
|
||||||
|
req_sigs += 20
|
||||||
|
n, m = 0, 0
|
||||||
|
if last:
|
||||||
|
last -= 1
|
||||||
|
s += 1
|
||||||
|
return {"nType": 7, "type": "NON_STANDARD", "reqSigs": req_sigs, "script": script}
|
||||||
|
|
||||||
|
|
||||||
|
def decode_script(script, asm=False):
|
||||||
|
"""
|
||||||
|
Decode script to ASM format or to human readable OPCODES string.
|
||||||
|
|
||||||
|
:param script: script in bytes string or HEX encoded string format.
|
||||||
|
:param asm: (optional) If set to True decode to ASM format, by default set to False.
|
||||||
|
:return: script in ASM format string or OPCODES string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if isinstance(script, str):
|
||||||
|
try:
|
||||||
|
script = bytes.fromhex(script)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if not isinstance(script, bytes):
|
||||||
|
raise TypeError("script invalid")
|
||||||
|
l = len(script)
|
||||||
|
s = 0
|
||||||
|
result = []
|
||||||
|
append = result.append
|
||||||
|
while l - s > 0:
|
||||||
|
if script[s] < 0x4c and script[s]:
|
||||||
|
if asm:
|
||||||
|
append(script[s + 1:s + 1 + script[s]].hex())
|
||||||
|
else:
|
||||||
|
append('[%s]' % script[s])
|
||||||
|
s += script[s] + 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if script[s] == OPCODE["OP_PUSHDATA1"]:
|
||||||
|
ld = script[s + 1]
|
||||||
|
if asm:
|
||||||
|
append(script[s + 1:s + 1 + ld].hex())
|
||||||
|
else:
|
||||||
|
append(RAW_OPCODE[script[s]])
|
||||||
|
append('[%s]' % ld)
|
||||||
|
s += 1 + script[s + 1] + 1
|
||||||
|
elif script[s] == OPCODE["OP_PUSHDATA2"]:
|
||||||
|
|
||||||
|
ld = struct.unpack('<H', script[s + 1: s + 3])[0]
|
||||||
|
if asm:
|
||||||
|
append(script[s + 1:s + 1 + ld].hex())
|
||||||
|
else:
|
||||||
|
append(RAW_OPCODE[script[s]])
|
||||||
|
append('[%s]' % ld)
|
||||||
|
s += 2 + 1 + ld
|
||||||
|
elif script[s] == OPCODE["OP_PUSHDATA4"]:
|
||||||
|
ld = struct.unpack('<L', script[s + 1: s + 5])[0]
|
||||||
|
if asm:
|
||||||
|
append(script[s + 1:s + 1 + ld].hex())
|
||||||
|
else:
|
||||||
|
append(RAW_OPCODE[script[s]])
|
||||||
|
append('[%s]' % ld)
|
||||||
|
s += 5 + 1 + ld
|
||||||
|
else:
|
||||||
|
append(RAW_OPCODE[script[s]])
|
||||||
|
s += 1
|
||||||
|
return ' '.join(result)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_from_script(script, sub_script):
|
||||||
|
"""
|
||||||
|
Decode OPCODE or subscript from script.
|
||||||
|
|
||||||
|
:param script: traget script in bytes or HEX encoded string.
|
||||||
|
:param sub_script: sub_script which is necessary to remove from target script in bytes or HEX encoded string.
|
||||||
|
:return: script in bytes or HEX encoded string corresponding to the format of target script.
|
||||||
|
"""
|
||||||
|
if not sub_script:
|
||||||
|
return script
|
||||||
|
s_hex = False
|
||||||
|
if isinstance(script, str):
|
||||||
|
try:
|
||||||
|
script = bytes.fromhex(script)
|
||||||
|
s_hex = True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if isinstance(sub_script, str):
|
||||||
|
try:
|
||||||
|
sub_script = bytes.fromhex(sub_script)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not isinstance(script, bytes):
|
||||||
|
raise TypeError("script invalid")
|
||||||
|
if not isinstance(sub_script, bytes):
|
||||||
|
raise TypeError("sub_script invalid")
|
||||||
|
|
||||||
|
l = len(script)
|
||||||
|
ls = len(sub_script)
|
||||||
|
s = 0
|
||||||
|
k = 0
|
||||||
|
stack = []
|
||||||
|
result = []
|
||||||
|
while l - s > 0:
|
||||||
|
if script[s] < 0x4c and script[s]:
|
||||||
|
stack.append(script[s] + 1)
|
||||||
|
s += script[s] + 1
|
||||||
|
elif script[s] == OPCODE["OP_PUSHDATA1"]:
|
||||||
|
stack.append(1 + script[s + 1])
|
||||||
|
s += 1 + script[s + 1]
|
||||||
|
elif script[s] == OPCODE["OP_PUSHDATA2"]:
|
||||||
|
stack.append(2 + struct.unpack('<H', script[s: s + 2]))
|
||||||
|
s += 2 + struct.unpack('<H', script[s: s + 2])
|
||||||
|
elif script[s] == OPCODE["OP_PUSHDATA4"]:
|
||||||
|
stack.append(4 + struct.unpack('<L', script[s: s + 4]))
|
||||||
|
s += 4 + struct.unpack('<L', script[s: s + 4])
|
||||||
|
else:
|
||||||
|
stack.append(1)
|
||||||
|
s += 1
|
||||||
|
if s - k >= ls:
|
||||||
|
if script[k:s][:ls] == sub_script:
|
||||||
|
if s - k > ls:
|
||||||
|
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])
|
||||||
|
k += t
|
||||||
|
if script[k:s][:ls] == sub_script:
|
||||||
|
if s - k > ls:
|
||||||
|
result.append(script[k + ls:s])
|
||||||
|
else:
|
||||||
|
result.append(script[k:k + ls])
|
||||||
|
|
||||||
|
return b''.join(result) if not s_hex else b''.join(result).hex()
|
||||||
|
|
||||||
|
|
||||||
|
def script_to_hash(script, witness=False, hex=True):
|
||||||
|
"""
|
||||||
|
Encode script to hash HASH160 or SHA256 in dependency of the witness.
|
||||||
|
|
||||||
|
:param script: script in bytes or HEX encoded string.
|
||||||
|
:param witness: (optional) If set to True return SHA256 hash for P2WSH, by default is False.
|
||||||
|
:param hex: (optional) If set to True return key in HEX format, by default is True.
|
||||||
|
:param sub_script: sub_script which is necessary to remove from target script in bytes or HEX encoded string.
|
||||||
|
:return: script in bytes or HEX encoded string corresponding to the format of target script.
|
||||||
|
"""
|
||||||
|
if isinstance(script, str):
|
||||||
|
s = bytes.fromhex(script)
|
||||||
|
if witness:
|
||||||
|
return sha256(script, hex)
|
||||||
|
else:
|
||||||
|
return hash160(script, hex)
|
||||||
|
|
||||||
|
|
||||||
|
def op_push_data(data):
|
||||||
|
if len(data) <= 0x4b:
|
||||||
|
return b''.join([bytes([len(data)]), data])
|
||||||
|
elif len(data) <= 0xff:
|
||||||
|
return b''.join([OP_PUSHDATA1, bytes([len(data)]), data])
|
||||||
|
elif len(data) <= 0xffff:
|
||||||
|
return b''.join([OP_PUSHDATA2, int_to_bytes(len(data), byteorder="little"), data])
|
||||||
|
|
||||||
|
else:
|
||||||
|
return b''.join([OP_PUSHDATA4, int_to_bytes(len(data), byteorder="little"), data])
|
||||||
|
|
||||||
|
|
||||||
|
def get_multisig_public_keys(script):
|
||||||
|
pub_keys = []
|
||||||
|
s = get_stream(script)
|
||||||
|
o, d = read_opcode(s)
|
||||||
|
while o:
|
||||||
|
o, d = read_opcode(s)
|
||||||
|
if d:
|
||||||
|
pub_keys.append(d)
|
||||||
|
return pub_keys
|
||||||
|
|
||||||
|
|
||||||
|
def read_opcode(stream):
|
||||||
|
b = stream.read(1)
|
||||||
|
if not b:
|
||||||
|
return None, None
|
||||||
|
if b[0] <= 0x4b:
|
||||||
|
return b, stream.read(b[0])
|
||||||
|
elif b[0] == OP_PUSHDATA1:
|
||||||
|
return b, stream.read(stream.read(1)[0])
|
||||||
|
elif b[0] == OP_PUSHDATA2:
|
||||||
|
return b, stream.read(struct.unpack("<H", stream.read(2)[0]))
|
||||||
|
elif b[0] == OP_PUSHDATA4:
|
||||||
|
return b, stream.read(struct.unpack("<L", stream.read(4)[0]))
|
||||||
|
else:
|
||||||
|
return b, None
|
||||||
|
|
||||||
|
|
||||||
|
def verify_signature(sig, pub_key, msg):
|
||||||
|
"""
|
||||||
|
Verify signature for message and given public key
|
||||||
|
|
||||||
|
:param sig: signature in bytes or HEX encoded string.
|
||||||
|
:param pub_key: public key in bytes or HEX encoded string.
|
||||||
|
:param msg: message in bytes or HEX encoded string.
|
||||||
|
:return: boolean.
|
||||||
|
"""
|
||||||
|
if not isinstance(sig, bytes):
|
||||||
|
if isinstance(sig, bytearray):
|
||||||
|
sig = bytes(sig)
|
||||||
|
elif isinstance(sig, str):
|
||||||
|
sig = bytes.fromhex(sig)
|
||||||
|
else:
|
||||||
|
raise TypeError("signature must be a bytes or hex encoded string")
|
||||||
|
if not isinstance(pub_key, bytes):
|
||||||
|
if isinstance(pub_key, bytearray):
|
||||||
|
pub_key = bytes(pub_key)
|
||||||
|
elif isinstance(pub_key, str):
|
||||||
|
pub_key = bytes.fromhex(pub_key)
|
||||||
|
else:
|
||||||
|
raise TypeError("public key must be a bytes or hex encoded string")
|
||||||
|
if not isinstance(msg, bytes):
|
||||||
|
if isinstance(msg, bytearray):
|
||||||
|
msg = bytes(msg)
|
||||||
|
elif isinstance(msg, str):
|
||||||
|
msg = bytes.fromhex(msg)
|
||||||
|
else:
|
||||||
|
raise TypeError("message must be a bytes or hex encoded string")
|
||||||
|
|
||||||
|
raw_sig = ffi.new('secp256k1_ecdsa_signature *')
|
||||||
|
raw_pubkey = ffi.new('secp256k1_pubkey *')
|
||||||
|
if not secp256k1.secp256k1_ecdsa_signature_parse_der(ECDSA_CONTEXT_VERIFY, raw_sig, sig, len(sig)):
|
||||||
|
raise TypeError("signature must be DER encoded")
|
||||||
|
if not secp256k1.secp256k1_ec_pubkey_parse(ECDSA_CONTEXT_VERIFY, raw_pubkey, pub_key, len(pub_key)):
|
||||||
|
raise TypeError("public key format error")
|
||||||
|
result = secp256k1.secp256k1_ecdsa_verify(ECDSA_CONTEXT_VERIFY, raw_sig, msg, raw_pubkey)
|
||||||
|
return True if result else False
|
||||||
|
|
||||||
|
|
||||||
|
def sign_message(msg, private_key, hex=True):
|
||||||
|
"""
|
||||||
|
Sign message
|
||||||
|
|
||||||
|
:param msg: message to sign bytes or HEX encoded string.
|
||||||
|
:param private_key: private key (bytes, hex encoded string or WIF format)
|
||||||
|
:param hex: (optional) If set to True return key in HEX format, by default is True.
|
||||||
|
:return: DER encoded signature in bytes or HEX encoded string.
|
||||||
|
"""
|
||||||
|
if isinstance(msg, bytearray):
|
||||||
|
msg = bytes(msg)
|
||||||
|
if isinstance(msg, str):
|
||||||
|
try:
|
||||||
|
msg = bytes.fromhex(msg)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if not isinstance(msg, bytes):
|
||||||
|
raise TypeError("message must be a bytes or hex encoded string")
|
||||||
|
|
||||||
|
if isinstance(private_key, bytearray):
|
||||||
|
private_key = bytes(private_key)
|
||||||
|
if isinstance(private_key, str):
|
||||||
|
try:
|
||||||
|
private_key = bytes.fromhex(private_key)
|
||||||
|
except:
|
||||||
|
if is_wif_valid(private_key):
|
||||||
|
private_key = wif_to_private_key(private_key, hex=False)
|
||||||
|
if not isinstance(private_key, bytes):
|
||||||
|
raise TypeError("private key must be a bytes, hex encoded string or in WIF format")
|
||||||
|
|
||||||
|
raw_sig = ffi.new('secp256k1_ecdsa_signature *')
|
||||||
|
signed = secp256k1.secp256k1_ecdsa_sign(ECDSA_CONTEXT_SIGN, raw_sig, msg,
|
||||||
|
private_key, ffi.NULL, ffi.NULL)
|
||||||
|
if not signed:
|
||||||
|
raise RuntimeError("secp256k1 error")
|
||||||
|
len_sig = 74
|
||||||
|
output = ffi.new('unsigned char[%d]' % len_sig)
|
||||||
|
outputlen = ffi.new('size_t *', len_sig)
|
||||||
|
res = secp256k1.secp256k1_ecdsa_signature_serialize_der(ECDSA_CONTEXT_SIGN,
|
||||||
|
output, outputlen, raw_sig)
|
||||||
|
if not res:
|
||||||
|
raise RuntimeError("secp256k1 error")
|
||||||
|
signature = bytes(ffi.buffer(output, outputlen[0]))
|
||||||
|
raw_sig = ffi.new('secp256k1_ecdsa_signature *')
|
||||||
|
return signature.hex() if hex else signature
|
||||||
|
|
||||||
|
|
||||||
|
def public_key_recovery(signature, messsage, rec_id, compressed=True, hex=True):
|
||||||
|
if isinstance(signature, str):
|
||||||
|
signature = bytes.fromhex(signature)
|
||||||
|
if isinstance(messsage, str):
|
||||||
|
messsage = bytes.fromhex(messsage)
|
||||||
|
raw_sig = ffi.new('secp256k1_ecdsa_signature *')
|
||||||
|
r = secp256k1.secp256k1_ecdsa_signature_parse_der(ECDSA_CONTEXT_SIGN,
|
||||||
|
raw_sig,
|
||||||
|
signature,
|
||||||
|
len(signature))
|
||||||
|
if not r:
|
||||||
|
raise RuntimeError("secp256k1 error")
|
||||||
|
compact_sig = ffi.new('unsigned char[%d]' % 64)
|
||||||
|
r = secp256k1.secp256k1_ecdsa_signature_serialize_compact(ECDSA_CONTEXT_VERIFY,
|
||||||
|
compact_sig,
|
||||||
|
raw_sig)
|
||||||
|
if not r:
|
||||||
|
raise RuntimeError("secp256k1 error")
|
||||||
|
|
||||||
|
recover_sig = ffi.new('secp256k1_ecdsa_recoverable_signature *')
|
||||||
|
t = secp256k1.secp256k1_ecdsa_recoverable_signature_parse_compact(
|
||||||
|
ECDSA_CONTEXT_ALL, recover_sig, compact_sig, rec_id)
|
||||||
|
if not r:
|
||||||
|
raise RuntimeError("secp256k1 error")
|
||||||
|
|
||||||
|
pubkey_ptr = ffi.new('secp256k1_pubkey *')
|
||||||
|
t = secp256k1.secp256k1_ecdsa_recover(
|
||||||
|
ECDSA_CONTEXT_ALL, pubkey_ptr, recover_sig, messsage)
|
||||||
|
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
|
||||||
|
if bytes(ffi.buffer(pubkey_ptr.data, 64)) == b"\x00" * 64:
|
||||||
|
return None
|
||||||
|
r = secp256k1.secp256k1_ec_pubkey_serialize(ECDSA_CONTEXT_VERIFY, pubkey, outlen, pubkey_ptr, compflag)
|
||||||
|
if not r:
|
||||||
|
raise RuntimeError("secp256k1 error")
|
||||||
|
pub = bytes(ffi.buffer(pubkey, len_key))
|
||||||
|
return pub.hex() if hex else pub
|
||||||
|
|
||||||
|
|
||||||
|
def is_valid_signature_encoding(sig):
|
||||||
|
"""
|
||||||
|
Check is valid signature encoded in DER format
|
||||||
|
|
||||||
|
:param sig: signature in bytes or HEX encoded string.
|
||||||
|
:return: boolean.
|
||||||
|
"""
|
||||||
|
# Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
|
||||||
|
# * total-length: 1-byte length descriptor of everything that follows,
|
||||||
|
# excluding the sighash byte.
|
||||||
|
# * R-length: 1-byte length descriptor of the R value that follows.
|
||||||
|
# * R: arbitrary-length big-endian encoded R value. It must use the shortest
|
||||||
|
# possible encoding for a positive integers (which means no null bytes at
|
||||||
|
# the start, except a single one when the next byte has its highest bit set).
|
||||||
|
# * S-length: 1-byte length descriptor of the S value that follows.
|
||||||
|
# * S: arbitrary-length big-endian encoded S value. The same rules apply.
|
||||||
|
# * sighash: 1-byte value indicating what data is hashed (not part of the DER
|
||||||
|
# signature)
|
||||||
|
length = len(sig)
|
||||||
|
# Minimum and maximum size constraints.
|
||||||
|
if (length < 9) or (length > 73):
|
||||||
|
return False
|
||||||
|
# A signature is of type 0x30 (compound).
|
||||||
|
if sig[0] != 0x30:
|
||||||
|
return False
|
||||||
|
# Make sure the length covers the entire signature.
|
||||||
|
if sig[1] != (length - 3):
|
||||||
|
return False
|
||||||
|
# Extract the length of the R element.
|
||||||
|
len_r = sig[3]
|
||||||
|
# Make sure the length of the S element is still inside the signature.
|
||||||
|
if (5 + len_r) >= length:
|
||||||
|
return False
|
||||||
|
# Extract the length of the S element.
|
||||||
|
len_s = sig[5 + len_r]
|
||||||
|
# Verify that the length of the signature matches the sum of the length
|
||||||
|
# of the elements.
|
||||||
|
if (len_r + len_s + 7) != length:
|
||||||
|
return False
|
||||||
|
# Check whether the R element is an integer.
|
||||||
|
if sig[2] != 0x02:
|
||||||
|
return False
|
||||||
|
# Zero-length integers are not allowed for R.
|
||||||
|
if len_r == 0:
|
||||||
|
return False
|
||||||
|
# Negative numbers are not allowed for R.
|
||||||
|
if sig[4] & 0x80:
|
||||||
|
return False
|
||||||
|
# Null bytes at the start of R are not allowed, unless R would
|
||||||
|
# otherwise be interpreted as a negative number.
|
||||||
|
if (len_r > 1) and (sig[4] == 0x00) and (not sig[5] & 0x80):
|
||||||
|
return False
|
||||||
|
# Check whether the S element is an integer.
|
||||||
|
if sig[len_r + 4] != 0x02:
|
||||||
|
return False
|
||||||
|
# Zero-length integers are not allowed for S.
|
||||||
|
if len_s == 0:
|
||||||
|
return False
|
||||||
|
# Negative numbers are not allowed for S.
|
||||||
|
if sig[len_r + 6] & 0x80:
|
||||||
|
return False
|
||||||
|
# Null bytes at the start of S are not allowed, unless S would otherwise be
|
||||||
|
# interpreted as a negative number.
|
||||||
|
if (len_s > 1) and (sig[len_r + 6] == 0x00) and (not sig[len_r + 7] & 0x80):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
347
pybtc/functions/tools.py
Normal file
347
pybtc/functions/tools.py
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
import math
|
||||||
|
import io
|
||||||
|
import struct
|
||||||
|
|
||||||
|
|
||||||
|
def rh2s(raw_hash):
|
||||||
|
"""
|
||||||
|
Encode raw transaction hash to HEX string with bytes order change
|
||||||
|
|
||||||
|
:param raw_hash: transaction hash in bytes string.
|
||||||
|
:return: HEX encoded string.
|
||||||
|
"""
|
||||||
|
return raw_hash[::-1].hex()
|
||||||
|
|
||||||
|
|
||||||
|
def s2rh(hash_string):
|
||||||
|
"""
|
||||||
|
Decode HEX transaction hash to bytes with byte order change
|
||||||
|
|
||||||
|
:param raw_hash: transaction hash in bytes string.
|
||||||
|
:return: bytes string.
|
||||||
|
"""
|
||||||
|
return bytes.fromhex(hash_string)[::-1]
|
||||||
|
|
||||||
|
|
||||||
|
def s2rh_step4(hash_string):
|
||||||
|
h = bytes.fromhex(hash_string)
|
||||||
|
return reverse_hash(h)
|
||||||
|
|
||||||
|
|
||||||
|
def reverse_hash(raw_hash):
|
||||||
|
"""
|
||||||
|
Reverse hash order
|
||||||
|
|
||||||
|
:param raw_hash: bytes string.
|
||||||
|
:return: bytes string.
|
||||||
|
"""
|
||||||
|
return struct.pack('>IIIIIIII', *struct.unpack('>IIIIIIII', raw_hash)[::-1])[::-1]
|
||||||
|
|
||||||
|
|
||||||
|
def bytes_needed(n):
|
||||||
|
"""
|
||||||
|
Calculate bytes needed to convert integer to bytes.
|
||||||
|
|
||||||
|
:param n: integer.
|
||||||
|
:return: integer.
|
||||||
|
"""
|
||||||
|
if n == 0:
|
||||||
|
return 1
|
||||||
|
return math.ceil(n.bit_length()/8)
|
||||||
|
|
||||||
|
|
||||||
|
def int_to_bytes(i, byteorder='big'):
|
||||||
|
"""
|
||||||
|
Convert integer to bytes.
|
||||||
|
|
||||||
|
:param n: integer.
|
||||||
|
:param byteorder: (optional) byte order 'big' or 'little', by default 'big'.
|
||||||
|
:return: bytes.
|
||||||
|
"""
|
||||||
|
return i.to_bytes(bytes_needed(i), byteorder=byteorder, signed=False)
|
||||||
|
|
||||||
|
|
||||||
|
def bytes_to_int(i, byteorder='big'):
|
||||||
|
"""
|
||||||
|
Convert bytes to integer.
|
||||||
|
|
||||||
|
:param i: bytes.
|
||||||
|
:param byteorder: (optional) byte order 'big' or 'little', by default 'big'.
|
||||||
|
:return: integer.
|
||||||
|
"""
|
||||||
|
return int.from_bytes(i, byteorder=byteorder, signed=False)
|
||||||
|
|
||||||
|
|
||||||
|
# variable integer
|
||||||
|
|
||||||
|
def int_to_var_int(i):
|
||||||
|
"""
|
||||||
|
Convert integer to variable integer
|
||||||
|
|
||||||
|
:param i: integer.
|
||||||
|
:return: bytes.
|
||||||
|
"""
|
||||||
|
if i < 0xfd:
|
||||||
|
return struct.pack('<B', i)
|
||||||
|
if i <= 0xffff:
|
||||||
|
return b'\xfd%s' % struct.pack('<H', i)
|
||||||
|
if i <= 0xffffffff:
|
||||||
|
return b'\xfe%s' % struct.pack('<L', i)
|
||||||
|
return b'\xff%s' % struct.pack('<Q', i)
|
||||||
|
|
||||||
|
|
||||||
|
def var_int_to_int(data):
|
||||||
|
"""
|
||||||
|
Convert variable integer to integer
|
||||||
|
|
||||||
|
:param data: bytes variable integer.
|
||||||
|
:return: integer.
|
||||||
|
"""
|
||||||
|
if data[0] == 0xfd:
|
||||||
|
return struct.unpack('<H', data[1:3])[0]
|
||||||
|
elif data[0] == 0xfe:
|
||||||
|
return struct.unpack('<L', data[1:5])[0]
|
||||||
|
elif data[0] == 0xff:
|
||||||
|
return struct.unpack('<Q', data[1:9])[0]
|
||||||
|
return data[0]
|
||||||
|
|
||||||
|
|
||||||
|
def var_int_len(n):
|
||||||
|
"""
|
||||||
|
Get variable integer length in bytes from integer value
|
||||||
|
|
||||||
|
:param n: integer.
|
||||||
|
:return: integer.
|
||||||
|
"""
|
||||||
|
if n <= 0xfc:
|
||||||
|
return 1
|
||||||
|
if n <= 0xffff:
|
||||||
|
return 3
|
||||||
|
elif n <= 0xffffffff:
|
||||||
|
return 5
|
||||||
|
return 9
|
||||||
|
|
||||||
|
|
||||||
|
def get_var_int_len(bytes):
|
||||||
|
"""
|
||||||
|
Get variable integer length in bytes from bytes
|
||||||
|
|
||||||
|
:param bytes: bytes.
|
||||||
|
:return: integer.
|
||||||
|
"""
|
||||||
|
if bytes[0] == 253:
|
||||||
|
return 3
|
||||||
|
elif bytes[0] == 254:
|
||||||
|
return 5
|
||||||
|
elif bytes[0] == 255:
|
||||||
|
return 9
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def read_var_int(stream):
|
||||||
|
"""
|
||||||
|
Read variable integer from io.BytesIO stream to bytes
|
||||||
|
|
||||||
|
:param stream: io.BytesIO stream.
|
||||||
|
:return: bytes.
|
||||||
|
"""
|
||||||
|
l = stream.read(1)
|
||||||
|
bytes_length = get_var_int_len(l)
|
||||||
|
return b"%s%s" % (l, stream.read(bytes_length - 1))
|
||||||
|
|
||||||
|
|
||||||
|
def read_var_list(stream, data_type):
|
||||||
|
"""
|
||||||
|
Read variable integer list from io.BytesIO stream to bytes
|
||||||
|
|
||||||
|
:param stream: io.BytesIO stream.
|
||||||
|
:param data_type: list data type.
|
||||||
|
:return: list of data_type.
|
||||||
|
"""
|
||||||
|
count = var_int_to_int(read_var_int(stream))
|
||||||
|
return [data_type.deserialize(stream) for i in range(count)]
|
||||||
|
|
||||||
|
# compressed integer
|
||||||
|
|
||||||
|
|
||||||
|
def int_to_c_int(n, base_bytes=1):
|
||||||
|
"""
|
||||||
|
Convert integer to compresed integer
|
||||||
|
|
||||||
|
:param n: integer.
|
||||||
|
:param base_bytes: len of bytes base from which start compression.
|
||||||
|
:return: bytes.
|
||||||
|
"""
|
||||||
|
if n == 0:
|
||||||
|
return b'\x00'
|
||||||
|
else:
|
||||||
|
l = n.bit_length() + 1
|
||||||
|
min_bits = base_bytes * 8 - 1
|
||||||
|
if l <= min_bits + 1:
|
||||||
|
return n.to_bytes(base_bytes, byteorder="big")
|
||||||
|
prefix = 0
|
||||||
|
payload_bytes = math.ceil((l)/8) - base_bytes
|
||||||
|
extra_bytes = int(math.ceil((l+payload_bytes)/8) - base_bytes)
|
||||||
|
for i in range(extra_bytes):
|
||||||
|
prefix += 2 ** i
|
||||||
|
if l < base_bytes * 8:
|
||||||
|
l = base_bytes * 8
|
||||||
|
prefix = prefix << l
|
||||||
|
if prefix.bit_length() % 8:
|
||||||
|
prefix = prefix << 8 - prefix.bit_length() % 8
|
||||||
|
n ^= prefix
|
||||||
|
return n.to_bytes(math.ceil(n.bit_length()/8), byteorder="big")
|
||||||
|
|
||||||
|
|
||||||
|
def c_int_to_int(b, base_bytes=1):
|
||||||
|
"""
|
||||||
|
Convert compressed integer bytes to integer
|
||||||
|
|
||||||
|
:param b: compressed integer bytes.
|
||||||
|
:param base_bytes: len of bytes base from which start compression.
|
||||||
|
:return: integer.
|
||||||
|
"""
|
||||||
|
byte_length = 0
|
||||||
|
f = 0
|
||||||
|
while True:
|
||||||
|
v = b[f]
|
||||||
|
if v == 0xff:
|
||||||
|
byte_length += 8
|
||||||
|
f += 1
|
||||||
|
continue
|
||||||
|
while v & 0b10000000:
|
||||||
|
byte_length += 1
|
||||||
|
v = v << 1
|
||||||
|
break
|
||||||
|
n = int.from_bytes(b[:byte_length+base_bytes], byteorder="big")
|
||||||
|
if byte_length:
|
||||||
|
return n & ((1 << (byte_length+base_bytes) * 8 - byte_length) - 1)
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
def c_int_len(n, base_bytes=1):
|
||||||
|
"""
|
||||||
|
Get length of compressed integer from integer value
|
||||||
|
|
||||||
|
:param n: bytes.
|
||||||
|
:param base_bytes: len of bytes base from which start compression.
|
||||||
|
:return: integer.
|
||||||
|
"""
|
||||||
|
if n == 0:
|
||||||
|
return 1
|
||||||
|
l = n.bit_length() + 1
|
||||||
|
min_bits = base_bytes * 8 - 1
|
||||||
|
if l <= min_bits + 1:
|
||||||
|
return 1
|
||||||
|
payload_bytes = math.ceil((l)/8) - base_bytes
|
||||||
|
return int(math.ceil((l+payload_bytes)/8))
|
||||||
|
|
||||||
|
|
||||||
|
# generic big endian MPI format
|
||||||
|
def bn_bytes(v, have_ext=False):
|
||||||
|
ext = 0
|
||||||
|
if have_ext:
|
||||||
|
ext = 1
|
||||||
|
return ((v.bit_length() + 7) // 8) + ext
|
||||||
|
|
||||||
|
|
||||||
|
def bn2bin(v):
|
||||||
|
s = bytearray()
|
||||||
|
i = bn_bytes(v)
|
||||||
|
while i > 0:
|
||||||
|
s.append((v >> ((i - 1) * 8)) & 0xff)
|
||||||
|
i -= 1
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def bin2bn(s):
|
||||||
|
l = 0
|
||||||
|
for ch in s:
|
||||||
|
l = (l << 8) | ch
|
||||||
|
return l
|
||||||
|
|
||||||
|
|
||||||
|
def bn2mpi(v):
|
||||||
|
have_ext = False
|
||||||
|
if v.bit_length() > 0:
|
||||||
|
have_ext = (v.bit_length() & 0x07) == 0
|
||||||
|
neg = False
|
||||||
|
if v < 0:
|
||||||
|
neg = True
|
||||||
|
v = -v
|
||||||
|
s = struct.pack(b">I", bn_bytes(v, have_ext))
|
||||||
|
ext = bytearray()
|
||||||
|
if have_ext:
|
||||||
|
ext.append(0)
|
||||||
|
v_bin = bn2bin(v)
|
||||||
|
if neg:
|
||||||
|
if have_ext:
|
||||||
|
ext[0] |= 0x80
|
||||||
|
else:
|
||||||
|
v_bin[0] |= 0x80
|
||||||
|
return s + ext + v_bin
|
||||||
|
|
||||||
|
|
||||||
|
def mpi2bn(s):
|
||||||
|
if len(s) < 4:
|
||||||
|
return None
|
||||||
|
s_size = bytes(s[:4])
|
||||||
|
v_len = struct.unpack(b">I", s_size)[0]
|
||||||
|
if len(s) != (v_len + 4):
|
||||||
|
return None
|
||||||
|
if v_len == 0:
|
||||||
|
return 0
|
||||||
|
v_str = bytearray(s[4:])
|
||||||
|
neg = False
|
||||||
|
i = v_str[0]
|
||||||
|
if i & 0x80:
|
||||||
|
neg = True
|
||||||
|
i &= ~0x80
|
||||||
|
v_str[0] = i
|
||||||
|
v = bin2bn(v_str)
|
||||||
|
|
||||||
|
if neg:
|
||||||
|
return -v
|
||||||
|
return v
|
||||||
|
|
||||||
|
# bitcoin-specific little endian format, with implicit size
|
||||||
|
|
||||||
|
|
||||||
|
def mpi2vch(s):
|
||||||
|
r = s[4:] # strip size
|
||||||
|
# if r:
|
||||||
|
r = r[::-1] # reverse string, converting BE->LE
|
||||||
|
# else: r=b'\x00'
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def bn2vch(v):
|
||||||
|
return bytes(mpi2vch(bn2mpi(v)))
|
||||||
|
|
||||||
|
|
||||||
|
def vch2mpi(s):
|
||||||
|
r = struct.pack(b">I", len(s)) # size
|
||||||
|
r += s[::-1] # reverse string, converting LE->BE
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def vch2bn(s):
|
||||||
|
return mpi2bn(vch2mpi(s))
|
||||||
|
|
||||||
|
|
||||||
|
def i2b(i): return bn2vch(i)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
raise TypeError
|
||||||
|
return stream
|
||||||
|
|
||||||
@ -6,8 +6,9 @@ from struct import pack, unpack
|
|||||||
from hashlib import pbkdf2_hmac
|
from hashlib import pbkdf2_hmac
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .tools import private_to_public_key, is_public_key_valid, encode_base58, decode_base58, private_key_to_wif
|
from .functions import *
|
||||||
from .hash import hmac_sha512, hash160, double_sha256, sha256, double_sha256
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
from binascii import hexlify
|
|
||||||
|
|
||||||
OPCODE = dict()
|
OPCODE = dict()
|
||||||
|
|
||||||
# push opcodes
|
# push opcodes
|
||||||
@ -152,7 +150,7 @@ OPCODE["OP_INVALIDOPCODE"] = 0xff
|
|||||||
|
|
||||||
RAW_OPCODE = dict((OPCODE[i], i) for i in OPCODE)
|
RAW_OPCODE = dict((OPCODE[i], i) for i in OPCODE)
|
||||||
BYTE_OPCODE = dict((i, bytes([OPCODE[i]])) for i in OPCODE)
|
BYTE_OPCODE = dict((i, bytes([OPCODE[i]])) for i in OPCODE)
|
||||||
HEX_OPCODE = dict((i, hexlify(bytes([OPCODE[i]])).decode()) for i in OPCODE)
|
HEX_OPCODE = dict((i, bytes([OPCODE[i]]).hex()) for i in OPCODE)
|
||||||
|
|
||||||
OP_FALSE = BYTE_OPCODE["OP_FALSE"]
|
OP_FALSE = BYTE_OPCODE["OP_FALSE"]
|
||||||
OP_0 = BYTE_OPCODE["OP_0"]
|
OP_0 = BYTE_OPCODE["OP_0"]
|
||||||
|
|||||||
1413
pybtc/tools.py
1413
pybtc/tools.py
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,8 @@
|
|||||||
|
|
||||||
from struct import unpack
|
from struct import unpack
|
||||||
import json
|
import json
|
||||||
from .tools import *
|
from .functions import *
|
||||||
from .address import PrivateKey, Address, PublicKey, ScriptAddress
|
from .address import PrivateKey, Address, PublicKey, ScriptAddress
|
||||||
from binascii import hexlify, unhexlify
|
|
||||||
|
|
||||||
|
|
||||||
class Transaction(dict):
|
class Transaction(dict):
|
||||||
@ -70,7 +69,7 @@ class Transaction(dict):
|
|||||||
self["vIn"][k]["txId"] = stream.read(32)
|
self["vIn"][k]["txId"] = stream.read(32)
|
||||||
self["vIn"][k]["vOut"] = unpack('<L', stream.read(4))[0]
|
self["vIn"][k]["vOut"] = unpack('<L', stream.read(4))[0]
|
||||||
self["vIn"][k]["scriptSig"] = stream.read(var_int_to_int(read_var_int(stream)))
|
self["vIn"][k]["scriptSig"] = stream.read(var_int_to_int(read_var_int(stream)))
|
||||||
(self["vIn"][k]["sequence"],) = unpack('<L', stream.read(4))
|
self["vIn"][k]["sequence"] = unpack('<L', stream.read(4))[0]
|
||||||
|
|
||||||
# outputs
|
# outputs
|
||||||
for k in range(var_int_to_int(read_var_int(stream))):
|
for k in range(var_int_to_int(read_var_int(stream))):
|
||||||
@ -143,17 +142,17 @@ class Transaction(dict):
|
|||||||
if type(self["hash"]) == bytes:
|
if type(self["hash"]) == bytes:
|
||||||
self["hash"] = rh2s(self["hash"])
|
self["hash"] = rh2s(self["hash"])
|
||||||
if type(self["rawTx"]) == bytes:
|
if type(self["rawTx"]) == bytes:
|
||||||
self["rawTx"] = hexlify(self["rawTx"]).decode()
|
self["rawTx"] = self["rawTx"].hex()
|
||||||
for i in self["vIn"]:
|
for i in self["vIn"]:
|
||||||
if type(self["vIn"][i]["txId"]) == bytes:
|
if type(self["vIn"][i]["txId"]) == bytes:
|
||||||
self["vIn"][i]["txId"] = rh2s(self["vIn"][i]["txId"])
|
self["vIn"][i]["txId"] = rh2s(self["vIn"][i]["txId"])
|
||||||
if type(self["vIn"][i]["scriptSig"]) == bytes:
|
if type(self["vIn"][i]["scriptSig"]) == bytes:
|
||||||
self["vIn"][i]["scriptSig"] = hexlify(self["vIn"][i]["scriptSig"]).decode()
|
self["vIn"][i]["scriptSig"] = self["vIn"][i]["scriptSig"].hex()
|
||||||
try:
|
try:
|
||||||
t = list()
|
t = list()
|
||||||
for w in self["vIn"][i]["txInWitness"]:
|
for w in self["vIn"][i]["txInWitness"]:
|
||||||
if type(w) == bytes:
|
if type(w) == bytes:
|
||||||
w = hexlify(w).decode()
|
w = w.hex()
|
||||||
t.append(w)
|
t.append(w)
|
||||||
self["vIn"][i]["txInWitness"] = t
|
self["vIn"][i]["txInWitness"] = t
|
||||||
|
|
||||||
@ -161,7 +160,7 @@ class Transaction(dict):
|
|||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
if type(self["vIn"][i]["addressHash"]) == bytes:
|
if type(self["vIn"][i]["addressHash"]) == bytes:
|
||||||
self["vIn"][i]["addressHash"] = hexlify(self["vIn"][i]["addressHash"]).decode()
|
self["vIn"][i]["addressHash"] = self["vIn"][i]["addressHash"].hex()
|
||||||
sh = True if self["vIn"][i]["nType"] in (1, 5) else False
|
sh = True if self["vIn"][i]["nType"] in (1, 5) else False
|
||||||
witness_version = None if self["vIn"][i]["nType"] < 5 else 0
|
witness_version = None if self["vIn"][i]["nType"] < 5 else 0
|
||||||
self["vIn"][i]["address"] = hash_to_address(self["vIn"][i]["addressHash"],
|
self["vIn"][i]["address"] = hash_to_address(self["vIn"][i]["addressHash"],
|
||||||
@ -172,26 +171,26 @@ class Transaction(dict):
|
|||||||
pass
|
pass
|
||||||
if "scriptPubKey" in self["vIn"][i]:
|
if "scriptPubKey" in self["vIn"][i]:
|
||||||
if type(self["vIn"][i]["scriptPubKey"]) == bytes:
|
if type(self["vIn"][i]["scriptPubKey"]) == bytes:
|
||||||
self["vIn"][i]["scriptPubKey"] = hexlify(self["vIn"][i]["scriptPubKey"]).decode()
|
self["vIn"][i]["scriptPubKey"] = self["vIn"][i]["scriptPubKey"].hex()
|
||||||
self["vIn"][i]["scriptPubKeyOpcodes"] = decode_script(self["vIn"][i]["scriptPubKey"])
|
self["vIn"][i]["scriptPubKeyOpcodes"] = decode_script(self["vIn"][i]["scriptPubKey"])
|
||||||
self["vIn"][i]["scriptPubKeyAsm"] = decode_script(self["vIn"][i]["scriptPubKey"], 1)
|
self["vIn"][i]["scriptPubKeyAsm"] = decode_script(self["vIn"][i]["scriptPubKey"], 1)
|
||||||
if "redeemScript" in self["vIn"][i]:
|
if "redeemScript" in self["vIn"][i]:
|
||||||
if type(self["vIn"][i]["redeemScript"]) == bytes:
|
if type(self["vIn"][i]["redeemScript"]) == bytes:
|
||||||
self["vIn"][i]["redeemScript"] = hexlify(self["vIn"][i]["redeemScript"]).decode()
|
self["vIn"][i]["redeemScript"] = self["vIn"][i]["redeemScript"].hex()
|
||||||
self["vIn"][i]["redeemScriptOpcodes"] = decode_script(self["vIn"][i]["redeemScript"])
|
self["vIn"][i]["redeemScriptOpcodes"] = decode_script(self["vIn"][i]["redeemScript"])
|
||||||
self["vIn"][i]["redeemScriptAsm"] = decode_script(self["vIn"][i]["redeemScript"], 1)
|
self["vIn"][i]["redeemScriptAsm"] = decode_script(self["vIn"][i]["redeemScript"], 1)
|
||||||
if not self["coinbase"]:
|
if not self["coinbase"]:
|
||||||
if type(self["vIn"][i]["scriptSig"]) == bytes:
|
if type(self["vIn"][i]["scriptSig"]) == bytes:
|
||||||
self["vIn"][i]["scriptSig"] = hexlify(self["vIn"][i]["scriptSig"]).decode()
|
self["vIn"][i]["scriptSig"] = self["vIn"][i]["scriptSig"].hex()
|
||||||
self["vIn"][i]["scriptSigOpcodes"] = decode_script(self["vIn"][i]["scriptSig"])
|
self["vIn"][i]["scriptSigOpcodes"] = decode_script(self["vIn"][i]["scriptSig"])
|
||||||
self["vIn"][i]["scriptSigAsm"] = decode_script(self["vIn"][i]["scriptSig"], 1)
|
self["vIn"][i]["scriptSigAsm"] = decode_script(self["vIn"][i]["scriptSig"], 1)
|
||||||
|
|
||||||
for i in self["vOut"]:
|
for i in self["vOut"]:
|
||||||
if type(self["vOut"][i]["scriptPubKey"]) == bytes:
|
if type(self["vOut"][i]["scriptPubKey"]) == bytes:
|
||||||
self["vOut"][i]["scriptPubKey"] = hexlify(self["vOut"][i]["scriptPubKey"]).decode()
|
self["vOut"][i]["scriptPubKey"] = self["vOut"][i]["scriptPubKey"].hex()
|
||||||
try:
|
try:
|
||||||
if type(self["vOut"][i]["addressHash"]) == bytes:
|
if type(self["vOut"][i]["addressHash"]) == bytes:
|
||||||
self["vOut"][i]["addressHash"] = hexlify(self["vOut"][i]["addressHash"]).decode()
|
self["vOut"][i]["addressHash"] = self["vOut"][i]["addressHash"].hex()
|
||||||
sh = True if self["vOut"][i]["nType"] in (1, 5) else False
|
sh = True if self["vOut"][i]["nType"] in (1, 5) else False
|
||||||
witness_version = None if self["vOut"][i]["nType"] < 5 else 0
|
witness_version = None if self["vOut"][i]["nType"] < 5 else 0
|
||||||
self["vOut"][i]["address"] = hash_to_address(self["vOut"][i]["addressHash"],
|
self["vOut"][i]["address"] = hash_to_address(self["vOut"][i]["addressHash"],
|
||||||
@ -204,7 +203,7 @@ class Transaction(dict):
|
|||||||
self["vOut"][i]["scriptPubKeyAsm"] = decode_script(self["vOut"][i]["scriptPubKey"], 1)
|
self["vOut"][i]["scriptPubKeyAsm"] = decode_script(self["vOut"][i]["scriptPubKey"], 1)
|
||||||
if "data" in self:
|
if "data" in self:
|
||||||
if type(self["data"]) == bytes:
|
if type(self["data"]) == bytes:
|
||||||
self["data"] = hexlify(self["data"]).decode()
|
self["data"] = self["data"].hex()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def encode(self):
|
def encode(self):
|
||||||
@ -221,25 +220,25 @@ class Transaction(dict):
|
|||||||
if type(self["hash"]) == str:
|
if type(self["hash"]) == str:
|
||||||
self["hash"] = s2rh(self["hash"])
|
self["hash"] = s2rh(self["hash"])
|
||||||
if type(self["rawTx"]) == str:
|
if type(self["rawTx"]) == str:
|
||||||
self["rawTx"] = unhexlify(self["rawTx"])
|
self["rawTx"] = bytes.fromhex(self["rawTx"])
|
||||||
|
|
||||||
for i in self["vIn"]:
|
for i in self["vIn"]:
|
||||||
if type(self["vIn"][i]["txId"]) == str:
|
if type(self["vIn"][i]["txId"]) == str:
|
||||||
self["vIn"][i]["txId"] = s2rh(self["vIn"][i]["txId"])
|
self["vIn"][i]["txId"] = s2rh(self["vIn"][i]["txId"])
|
||||||
if type(self["vIn"][i]["scriptSig"]) == str:
|
if type(self["vIn"][i]["scriptSig"]) == str:
|
||||||
self["vIn"][i]["scriptSig"] = unhexlify(self["vIn"][i]["scriptSig"])
|
self["vIn"][i]["scriptSig"] = bytes.fromhex(self["vIn"][i]["scriptSig"])
|
||||||
try:
|
try:
|
||||||
t = list()
|
t = list()
|
||||||
for w in self["vIn"][i]["txInWitness"]:
|
for w in self["vIn"][i]["txInWitness"]:
|
||||||
if type(w) == str:
|
if type(w) == str:
|
||||||
w = unhexlify(w)
|
w = bytes.fromhex(w)
|
||||||
t.append(w)
|
t.append(w)
|
||||||
self["vIn"][i]["txInWitness"] = t
|
self["vIn"][i]["txInWitness"] = t
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
if type(self["vIn"][i]["addressHash"]) == str:
|
if type(self["vIn"][i]["addressHash"]) == str:
|
||||||
self["vIn"][i]["addressHash"] = unhexlify(self["vIn"][i]["addressHash"])
|
self["vIn"][i]["addressHash"] = bytes.fromhex(self["vIn"][i]["addressHash"])
|
||||||
if "address" in self["vIn"][i]:
|
if "address" in self["vIn"][i]:
|
||||||
del self["vIn"][i]["address"]
|
del self["vIn"][i]["address"]
|
||||||
except:
|
except:
|
||||||
@ -253,7 +252,7 @@ class Transaction(dict):
|
|||||||
if "scriptPubKeyAsm" in self["vIn"][i]:
|
if "scriptPubKeyAsm" in self["vIn"][i]:
|
||||||
del self["vIn"][i]["scriptPubKeyAsm"]
|
del self["vIn"][i]["scriptPubKeyAsm"]
|
||||||
if "scriptPubKey" in self["vIn"][i]:
|
if "scriptPubKey" in self["vIn"][i]:
|
||||||
self["vIn"][i]["scriptPubKey"] = unhexlify(self["vIn"][i]["scriptPubKey"])
|
self["vIn"][i]["scriptPubKey"] = bytes.fromhex(self["vIn"][i]["scriptPubKey"])
|
||||||
if "redeemScriptOpcodes" in self["vIn"][i]:
|
if "redeemScriptOpcodes" in self["vIn"][i]:
|
||||||
del self["vIn"][i]["redeemScriptOpcodes"]
|
del self["vIn"][i]["redeemScriptOpcodes"]
|
||||||
if "redeemScriptAsm" in self["vIn"][i]:
|
if "redeemScriptAsm" in self["vIn"][i]:
|
||||||
@ -263,10 +262,10 @@ class Transaction(dict):
|
|||||||
|
|
||||||
for i in self["vOut"]:
|
for i in self["vOut"]:
|
||||||
if type(self["vOut"][i]["scriptPubKey"]) == str:
|
if type(self["vOut"][i]["scriptPubKey"]) == str:
|
||||||
self["vOut"][i]["scriptPubKey"] = unhexlify(self["vOut"][i]["scriptPubKey"])
|
self["vOut"][i]["scriptPubKey"] = bytes.fromhex(self["vOut"][i]["scriptPubKey"])
|
||||||
try:
|
try:
|
||||||
if type(self["vOut"][i]["addressHash"]) == str:
|
if type(self["vOut"][i]["addressHash"]) == str:
|
||||||
self["vOut"][i]["addressHash"] = unhexlify(self["vOut"][i]["addressHash"])
|
self["vOut"][i]["addressHash"] = bytes.fromhex(self["vOut"][i]["addressHash"])
|
||||||
if "address" in self["vOut"][i]:
|
if "address" in self["vOut"][i]:
|
||||||
del self["vOut"][i]["address"]
|
del self["vOut"][i]["address"]
|
||||||
except:
|
except:
|
||||||
@ -278,7 +277,7 @@ class Transaction(dict):
|
|||||||
|
|
||||||
if "data" in self:
|
if "data" in self:
|
||||||
if type(self["data"]) == str:
|
if type(self["data"]) == str:
|
||||||
self["data"] = unhexlify(self["data"])
|
self["data"] = bytes.fromhex(self["data"])
|
||||||
self["format"] = "raw"
|
self["format"] = "raw"
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -286,7 +285,7 @@ class Transaction(dict):
|
|||||||
def get_stream(stream):
|
def get_stream(stream):
|
||||||
if type(stream) != io.BytesIO:
|
if type(stream) != io.BytesIO:
|
||||||
if type(stream) == str:
|
if type(stream) == str:
|
||||||
stream = unhexlify(stream)
|
stream = bytes.fromhex(stream)
|
||||||
if type(stream) == bytes:
|
if type(stream) == bytes:
|
||||||
stream = io.BytesIO(stream)
|
stream = io.BytesIO(stream)
|
||||||
else:
|
else:
|
||||||
@ -303,45 +302,46 @@ class Transaction(dict):
|
|||||||
:return str,bytes: serialized transaction in HEX or bytes.
|
:return str,bytes: serialized transaction in HEX or bytes.
|
||||||
"""
|
"""
|
||||||
chunks = []
|
chunks = []
|
||||||
chunks.append(struct.pack('<L', self["version"]))
|
append = chunks.append
|
||||||
|
append(struct.pack('<L', self["version"]))
|
||||||
if segwit and self["segwit"]:
|
if segwit and self["segwit"]:
|
||||||
chunks.append(b"\x00\x01")
|
append(b"\x00\x01")
|
||||||
chunks.append(int_to_var_int(len(self["vIn"])))
|
append(int_to_var_int(len(self["vIn"])))
|
||||||
for i in self["vIn"]:
|
for i in self["vIn"]:
|
||||||
if isinstance(self["vIn"][i]['txId'], bytes):
|
if isinstance(self["vIn"][i]['txId'], bytes):
|
||||||
chunks.append(self["vIn"][i]['txId'])
|
append(self["vIn"][i]['txId'])
|
||||||
else:
|
else:
|
||||||
chunks.append(s2rh(self["vIn"][i]['txId']))
|
append(s2rh(self["vIn"][i]['txId']))
|
||||||
chunks.append(struct.pack('<L', self["vIn"][i]['vOut']))
|
append(struct.pack('<L', self["vIn"][i]['vOut']))
|
||||||
if isinstance(self["vIn"][i]['scriptSig'], bytes):
|
if isinstance(self["vIn"][i]['scriptSig'], bytes):
|
||||||
chunks.append(int_to_var_int(len(self["vIn"][i]['scriptSig'])))
|
append(int_to_var_int(len(self["vIn"][i]['scriptSig'])))
|
||||||
chunks.append(self["vIn"][i]['scriptSig'])
|
append(self["vIn"][i]['scriptSig'])
|
||||||
else:
|
else:
|
||||||
chunks.append(int_to_var_int(int(len(self["vIn"][i]['scriptSig']) / 2)))
|
append(int_to_var_int(int(len(self["vIn"][i]['scriptSig']) / 2)))
|
||||||
chunks.append(unhexlify(self["vIn"][i]['scriptSig']))
|
append(bytes.fromhex(self["vIn"][i]['scriptSig']))
|
||||||
chunks.append(struct.pack('<L', self["vIn"][i]['sequence']))
|
append(struct.pack('<L', self["vIn"][i]['sequence']))
|
||||||
chunks.append(int_to_var_int(len(self["vOut"])))
|
append(int_to_var_int(len(self["vOut"])))
|
||||||
for i in self["vOut"]:
|
for i in self["vOut"]:
|
||||||
chunks.append(struct.pack('<Q', self["vOut"][i]['value']))
|
append(struct.pack('<Q', self["vOut"][i]['value']))
|
||||||
if isinstance(self["vOut"][i]['scriptPubKey'], bytes):
|
if isinstance(self["vOut"][i]['scriptPubKey'], bytes):
|
||||||
chunks.append(int_to_var_int(len(self["vOut"][i]['scriptPubKey'])))
|
append(int_to_var_int(len(self["vOut"][i]['scriptPubKey'])))
|
||||||
chunks.append(self["vOut"][i]['scriptPubKey'])
|
append(self["vOut"][i]['scriptPubKey'])
|
||||||
else:
|
else:
|
||||||
chunks.append(int_to_var_int(int(len(self["vOut"][i]['scriptPubKey']) / 2)))
|
append(int_to_var_int(int(len(self["vOut"][i]['scriptPubKey']) / 2)))
|
||||||
chunks.append(unhexlify(self["vOut"][i]['scriptPubKey']))
|
append(bytes.fromhex(self["vOut"][i]['scriptPubKey']))
|
||||||
if segwit and self["segwit"]:
|
if segwit and self["segwit"]:
|
||||||
for i in self["vIn"]:
|
for i in self["vIn"]:
|
||||||
chunks.append(int_to_var_int(len(self["vIn"][i]['txInWitness'])))
|
append(int_to_var_int(len(self["vIn"][i]['txInWitness'])))
|
||||||
for w in self["vIn"][i]['txInWitness']:
|
for w in self["vIn"][i]['txInWitness']:
|
||||||
if isinstance(w, bytes):
|
if isinstance(w, bytes):
|
||||||
chunks.append(int_to_var_int(len(w)))
|
append(int_to_var_int(len(w)))
|
||||||
chunks.append(w)
|
append(w)
|
||||||
else:
|
else:
|
||||||
chunks.append(int_to_var_int(int(len(w) / 2)))
|
append(int_to_var_int(int(len(w) / 2)))
|
||||||
chunks.append(unhexlify(w))
|
append(bytes.fromhex(w))
|
||||||
chunks.append(struct.pack('<L', self['lockTime']))
|
append(struct.pack('<L', self['lockTime']))
|
||||||
tx = b''.join(chunks)
|
tx = b''.join(chunks)
|
||||||
return tx if not hex else hexlify(tx).decode()
|
return tx if not hex else tx.hex()
|
||||||
|
|
||||||
def json(self):
|
def json(self):
|
||||||
"""
|
"""
|
||||||
@ -369,7 +369,7 @@ class Transaction(dict):
|
|||||||
raise TypeError("tx_id invalid")
|
raise TypeError("tx_id invalid")
|
||||||
|
|
||||||
if isinstance(script_sig, str):
|
if isinstance(script_sig, str):
|
||||||
script_sig = unhexlify(script_sig)
|
script_sig = bytes.fromhex(script_sig)
|
||||||
if not isinstance(script_sig, bytes) or not len(script_sig) <= 520:
|
if not isinstance(script_sig, bytes) or not len(script_sig) <= 520:
|
||||||
raise TypeError("script_sig invalid")
|
raise TypeError("script_sig invalid")
|
||||||
|
|
||||||
@ -392,9 +392,9 @@ class Transaction(dict):
|
|||||||
witness = []
|
witness = []
|
||||||
for w in tx_in_witness:
|
for w in tx_in_witness:
|
||||||
if isinstance(w, str):
|
if isinstance(w, str):
|
||||||
witness.append(unhexlify(w) if self["format"] == "raw" else w)
|
witness.append(bytes.fromhex(w) if self["format"] == "raw" else w)
|
||||||
else:
|
else:
|
||||||
witness.append(w if self["format"] == "raw" else unhexlify(w))
|
witness.append(w if self["format"] == "raw" else bytes.fromhex(w))
|
||||||
l += 1 + len(w)
|
l += 1 + len(w)
|
||||||
if len(w) >= 0x4c:
|
if len(w) >= 0x4c:
|
||||||
l += 1
|
l += 1
|
||||||
@ -412,13 +412,13 @@ class Transaction(dict):
|
|||||||
# script_pub_key
|
# script_pub_key
|
||||||
if script_pub_key:
|
if script_pub_key:
|
||||||
if isinstance(script_pub_key, str):
|
if isinstance(script_pub_key, str):
|
||||||
script_pub_key = unhexlify(script_pub_key)
|
script_pub_key = bytes.fromhex(script_pub_key)
|
||||||
if not isinstance(script_pub_key, bytes):
|
if not isinstance(script_pub_key, bytes):
|
||||||
raise TypeError("script_pub_key tx invalid")
|
raise TypeError("script_pub_key tx invalid")
|
||||||
|
|
||||||
if redeem_script:
|
if redeem_script:
|
||||||
if isinstance(redeem_script, str):
|
if isinstance(redeem_script, str):
|
||||||
redeem_script = unhexlify(redeem_script)
|
redeem_script = bytes.fromhex(redeem_script)
|
||||||
if not isinstance(redeem_script, bytes):
|
if not isinstance(redeem_script, bytes):
|
||||||
raise TypeError("redeem_script tx invalid")
|
raise TypeError("redeem_script tx invalid")
|
||||||
|
|
||||||
@ -448,15 +448,15 @@ class Transaction(dict):
|
|||||||
self["vIn"][k]["redeemScript"] = redeem_script
|
self["vIn"][k]["redeemScript"] = redeem_script
|
||||||
else:
|
else:
|
||||||
self["vIn"][k]["txId"] = rh2s(tx_id)
|
self["vIn"][k]["txId"] = rh2s(tx_id)
|
||||||
self["vIn"][k]["scriptSig"] = hexlify(script_sig).decode()
|
self["vIn"][k]["scriptSig"] = script_sig.hex()
|
||||||
self["vIn"][k]["scriptSigOpcodes"] = decode_script(script_sig)
|
self["vIn"][k]["scriptSigOpcodes"] = decode_script(script_sig)
|
||||||
self["vIn"][k]["scriptSigAsm"] = decode_script(script_sig, 1)
|
self["vIn"][k]["scriptSigAsm"] = decode_script(script_sig, 1)
|
||||||
if script_pub_key:
|
if script_pub_key:
|
||||||
self["vIn"][k]["scriptPubKey"] = hexlify(script_pub_key).decode()
|
self["vIn"][k]["scriptPubKey"] = script_pub_key.hex()
|
||||||
self["vIn"][k]["scriptPubKeyOpcodes"] = decode_script(script_pub_key)
|
self["vIn"][k]["scriptPubKeyOpcodes"] = decode_script(script_pub_key)
|
||||||
self["vIn"][k]["scriptPubKeyAsm"] = decode_script(script_pub_key, 1)
|
self["vIn"][k]["scriptPubKeyAsm"] = decode_script(script_pub_key, 1)
|
||||||
if redeem_script:
|
if redeem_script:
|
||||||
self["vIn"][k]["redeemScript"] = hexlify(redeem_script).decode()
|
self["vIn"][k]["redeemScript"] = redeem_script.hex()
|
||||||
self["vIn"][k]["redeemScriptOpcodes"] = decode_script(redeem_script)
|
self["vIn"][k]["redeemScriptOpcodes"] = decode_script(redeem_script)
|
||||||
self["vIn"][k]["redeemScriptAsm"] = decode_script(script_pub_key, 1)
|
self["vIn"][k]["redeemScriptAsm"] = decode_script(script_pub_key, 1)
|
||||||
if tx_in_witness:
|
if tx_in_witness:
|
||||||
@ -476,7 +476,7 @@ class Transaction(dict):
|
|||||||
assert amount >= 0 and amount <= MAX_AMOUNT
|
assert amount >= 0 and amount <= MAX_AMOUNT
|
||||||
if script_pub_key:
|
if script_pub_key:
|
||||||
if type(script_pub_key) == str:
|
if type(script_pub_key) == str:
|
||||||
script_pub_key = unhexlify(script_pub_key)
|
script_pub_key = bytes.fromhex(script_pub_key)
|
||||||
assert type(script_pub_key) == bytes
|
assert type(script_pub_key) == bytes
|
||||||
else:
|
else:
|
||||||
if type(address) == Address:
|
if type(address) == Address:
|
||||||
@ -500,12 +500,12 @@ class Transaction(dict):
|
|||||||
self["vOut"][k]["addressHash"] = s["addressHash"]
|
self["vOut"][k]["addressHash"] = s["addressHash"]
|
||||||
self["vOut"][k]["reqSigs"] = s["reqSigs"]
|
self["vOut"][k]["reqSigs"] = s["reqSigs"]
|
||||||
else:
|
else:
|
||||||
self["vOut"][k]["scriptPubKey"] = hexlify(script_pub_key).decode()
|
self["vOut"][k]["scriptPubKey"] = script_pub_key.hex()
|
||||||
if self["data"] is None:
|
if self["data"] is None:
|
||||||
if s["nType"] == 3:
|
if s["nType"] == 3:
|
||||||
self["data"] = hexlify(s["data"]).decode()
|
self["data"] = s["data"].hex()
|
||||||
if s["nType"] not in (3, 4, 7):
|
if s["nType"] not in (3, 4, 7):
|
||||||
self["vOut"][k]["addressHash"] = hexlify(s["addressHash"]).decode()
|
self["vOut"][k]["addressHash"] = s["addressHash"].hex()
|
||||||
self["vOut"][k]["reqSigs"] = s["reqSigs"]
|
self["vOut"][k]["reqSigs"] = s["reqSigs"]
|
||||||
self["vOut"][k]["scriptPubKeyOpcodes"] = decode_script(script_pub_key)
|
self["vOut"][k]["scriptPubKeyOpcodes"] = decode_script(script_pub_key)
|
||||||
self["vOut"][k]["scriptPubKeyAsm"] = decode_script(script_pub_key, 1)
|
self["vOut"][k]["scriptPubKeyAsm"] = decode_script(script_pub_key, 1)
|
||||||
@ -595,7 +595,7 @@ class Transaction(dict):
|
|||||||
else:
|
else:
|
||||||
st = parse_script(script_pub_key)
|
st = parse_script(script_pub_key)
|
||||||
if isinstance(script_pub_key, str):
|
if isinstance(script_pub_key, str):
|
||||||
script_pub_key = unhexlify(script_pub_key)
|
script_pub_key = bytes.fromhex(script_pub_key)
|
||||||
|
|
||||||
# sign input
|
# sign input
|
||||||
if st["type"] == "PUBKEY":
|
if st["type"] == "PUBKEY":
|
||||||
@ -615,7 +615,7 @@ class Transaction(dict):
|
|||||||
if self["format"] == "raw":
|
if self["format"] == "raw":
|
||||||
self["vIn"][n]["scriptSig"] = script_sig
|
self["vIn"][n]["scriptSig"] = script_sig
|
||||||
else:
|
else:
|
||||||
self["vIn"][n]["scriptSig"] = hexlify(script_sig).decode()
|
self["vIn"][n]["scriptSig"] = script_sig.hex()
|
||||||
self["vIn"][n]["scriptSigOpcodes"] = decode_script(script_sig)
|
self["vIn"][n]["scriptSigOpcodes"] = decode_script(script_sig)
|
||||||
self["vIn"][n]["scriptSigAsm"] = decode_script(script_sig, 1)
|
self["vIn"][n]["scriptSigAsm"] = decode_script(script_sig, 1)
|
||||||
self.__refresh__()
|
self.__refresh__()
|
||||||
@ -644,7 +644,7 @@ class Transaction(dict):
|
|||||||
else:
|
else:
|
||||||
raise RuntimeError("no redeem script")
|
raise RuntimeError("no redeem script")
|
||||||
if isinstance(redeem_script, str):
|
if isinstance(redeem_script, str):
|
||||||
redeem_script = unhexlify(redeem_script)
|
redeem_script = bytes.fromhex(redeem_script)
|
||||||
rst = parse_script(redeem_script)
|
rst = parse_script(redeem_script)
|
||||||
|
|
||||||
if p2sh_p2wsh:
|
if p2sh_p2wsh:
|
||||||
@ -677,14 +677,14 @@ class Transaction(dict):
|
|||||||
except:
|
except:
|
||||||
raise RuntimeError("no input amount")
|
raise RuntimeError("no input amount")
|
||||||
sighash = self.sig_hash_segwit(n, amount, script_pub_key=b"".join(s), sighash_type=sighash_type)
|
sighash = self.sig_hash_segwit(n, amount, script_pub_key=b"".join(s), sighash_type=sighash_type)
|
||||||
sighash = unhexlify(sighash) if isinstance(sighash, str) else sighash
|
sighash = bytes.fromhex(sighash) if isinstance(sighash, str) else sighash
|
||||||
signature = sign_message(sighash, private_key[0], 0) + bytes([sighash_type])
|
signature = sign_message(sighash, private_key[0], 0) + bytes([sighash_type])
|
||||||
|
|
||||||
self["segwit"] = True
|
self["segwit"] = True
|
||||||
if self["format"] == "raw":
|
if self["format"] == "raw":
|
||||||
self["vIn"][n]['txInWitness'] = [signature, public_key[0]]
|
self["vIn"][n]['txInWitness'] = [signature, public_key[0]]
|
||||||
else:
|
else:
|
||||||
self["vIn"][n]['txInWitness'] = [hexlify(signature).decode(), hexlify(public_key[0]).decode()]
|
self["vIn"][n]['txInWitness'] = [signature.hex(), public_key[0].hex()]
|
||||||
return op_push_data(redeem_script)
|
return op_push_data(redeem_script)
|
||||||
|
|
||||||
def __sign_p2sh_p2wsh(self, n, private_key, public_key,
|
def __sign_p2sh_p2wsh(self, n, private_key, public_key,
|
||||||
@ -708,15 +708,15 @@ class Transaction(dict):
|
|||||||
except:
|
except:
|
||||||
raise RuntimeError("no input amount")
|
raise RuntimeError("no input amount")
|
||||||
sighash = self.sig_hash_segwit(n, amount, script_pub_key=b"".join(s), sighash_type=sighash_type)
|
sighash = self.sig_hash_segwit(n, amount, script_pub_key=b"".join(s), sighash_type=sighash_type)
|
||||||
sighash = unhexlify(sighash) if isinstance(sighash, str) else sighash
|
sighash = bytes.fromhex(sighash) if isinstance(sighash, str) else sighash
|
||||||
signature = sign_message(sighash, private_key[0], 0) + bytes([sighash_type])
|
signature = sign_message(sighash, private_key[0], 0) + bytes([sighash_type])
|
||||||
self["segwit"] = True
|
self["segwit"] = True
|
||||||
if self["format"] == "raw":
|
if self["format"] == "raw":
|
||||||
self["vIn"][n]['txInWitness'] = [signature,
|
self["vIn"][n]['txInWitness'] = [signature,
|
||||||
public_key[0]]
|
public_key[0]]
|
||||||
else:
|
else:
|
||||||
self["vIn"][n]['txInWitness'] = [hexlify(signature).decode(),
|
self["vIn"][n]['txInWitness'] = [signature.hex(),
|
||||||
hexlify(public_key[0]).decode()]
|
public_key[0].hex()]
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
def __sign_p2wsh(self, n, private_key, public_key, script_pub_key, redeem_script, sighash_type, amount):
|
def __sign_p2wsh(self, n, private_key, public_key, script_pub_key, redeem_script, sighash_type, amount):
|
||||||
@ -727,7 +727,7 @@ class Transaction(dict):
|
|||||||
else:
|
else:
|
||||||
raise RuntimeError("no redeem script")
|
raise RuntimeError("no redeem script")
|
||||||
if isinstance(redeem_script, str):
|
if isinstance(redeem_script, str):
|
||||||
redeem_script = unhexlify(redeem_script)
|
redeem_script = bytes.fromhex(redeem_script)
|
||||||
rst = parse_script(redeem_script)
|
rst = parse_script(redeem_script)
|
||||||
if amount is None:
|
if amount is None:
|
||||||
try:
|
try:
|
||||||
@ -744,7 +744,7 @@ class Transaction(dict):
|
|||||||
def __sign_p2wsh_multisig(self, n, private_key, public_key, script_pub_key, redeem_script, sighash_type, amount):
|
def __sign_p2wsh_multisig(self, n, private_key, public_key, script_pub_key, redeem_script, sighash_type, amount):
|
||||||
script_code = int_to_var_int(len(redeem_script)) + redeem_script
|
script_code = int_to_var_int(len(redeem_script)) + redeem_script
|
||||||
sighash = self.sig_hash_segwit(n, amount, script_pub_key=script_code, sighash_type=sighash_type)
|
sighash = self.sig_hash_segwit(n, amount, script_pub_key=script_code, sighash_type=sighash_type)
|
||||||
sighash = unhexlify(sighash) if isinstance(sighash, str) else sighash
|
sighash = bytes.fromhex(sighash) if isinstance(sighash, str) else sighash
|
||||||
sig = [sign_message(sighash, p, 0) + bytes([sighash_type]) for p in private_key]
|
sig = [sign_message(sighash, p, 0) + bytes([sighash_type]) for p in private_key]
|
||||||
if "txInWitness" not in self["vIn"][n]:
|
if "txInWitness" not in self["vIn"][n]:
|
||||||
self["vIn"][n]["txInWitness"] = []
|
self["vIn"][n]["txInWitness"] = []
|
||||||
@ -753,7 +753,7 @@ class Transaction(dict):
|
|||||||
if self["format"] == "raw":
|
if self["format"] == "raw":
|
||||||
self["vIn"][n]['txInWitness'] = list(witness)
|
self["vIn"][n]['txInWitness'] = list(witness)
|
||||||
else:
|
else:
|
||||||
self["vIn"][n]["txInWitness"] = list([hexlify(w).decode() for w in witness])
|
self["vIn"][n]["txInWitness"] = list([w.hex() for w in witness])
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
def __sign_p2wsh_custom(self, n, private_key, public_key, script_pub_key, redeem_script, sighash_type, amount):
|
def __sign_p2wsh_custom(self, n, private_key, public_key, script_pub_key, redeem_script, sighash_type, amount):
|
||||||
@ -764,7 +764,7 @@ class Transaction(dict):
|
|||||||
self["segwit"] = True
|
self["segwit"] = True
|
||||||
script_code = int_to_var_int(len(redeem_script)) + redeem_script
|
script_code = int_to_var_int(len(redeem_script)) + redeem_script
|
||||||
sighash = self.sig_hash_segwit(n, amount, script_pub_key=script_code, sighash_type=sighash_type)
|
sighash = self.sig_hash_segwit(n, amount, script_pub_key=script_code, sighash_type=sighash_type)
|
||||||
sighash = unhexlify(sighash) if isinstance(sighash, str) else sighash
|
sighash = bytes.fromhex(sighash) if isinstance(sighash, str) else sighash
|
||||||
sig = [sign_message(sighash, p, 0) + bytes([sighash_type]) for p in private_key]
|
sig = [sign_message(sighash, p, 0) + bytes([sighash_type]) for p in private_key]
|
||||||
if "txInWitness" not in self["vIn"][n]:
|
if "txInWitness" not in self["vIn"][n]:
|
||||||
self["vIn"][n]["txInWitness"] = []
|
self["vIn"][n]["txInWitness"] = []
|
||||||
@ -778,7 +778,7 @@ class Transaction(dict):
|
|||||||
if self["format"] == "raw":
|
if self["format"] == "raw":
|
||||||
self["vIn"][n]['txInWitness'] = list(witness)
|
self["vIn"][n]['txInWitness'] = list(witness)
|
||||||
else:
|
else:
|
||||||
self["vIn"][n]["txInWitness"] = list([hexlify(w).decode() for w in witness])
|
self["vIn"][n]["txInWitness"] = list([w.hex() for w in witness])
|
||||||
# calculate P2SH redeem script from P2WSH redeem script
|
# calculate P2SH redeem script from P2WSH redeem script
|
||||||
return op_push_data(b"\x00" + op_push_data(sha256(redeem_script)))
|
return op_push_data(b"\x00" + op_push_data(sha256(redeem_script)))
|
||||||
|
|
||||||
@ -814,7 +814,7 @@ class Transaction(dict):
|
|||||||
else:
|
else:
|
||||||
for w in script_sig:
|
for w in script_sig:
|
||||||
if isinstance(w, str):
|
if isinstance(w, str):
|
||||||
w = unhexlify(w)
|
w = bytes.fromhex(w)
|
||||||
if w and is_valid_signature_encoding(w):
|
if w and is_valid_signature_encoding(w):
|
||||||
d = w[:-1]
|
d = w[:-1]
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
@ -822,8 +822,6 @@ class Transaction(dict):
|
|||||||
script_pub_key=script_code,
|
script_pub_key=script_code,
|
||||||
sighash_type=w[-1])
|
sighash_type=w[-1])
|
||||||
pk = public_key_recovery(d, sighash, i, hex=0)
|
pk = public_key_recovery(d, sighash, i, hex=0)
|
||||||
if pk is not None:
|
|
||||||
l = hexlify(pk)
|
|
||||||
if pk in pub_keys:
|
if pk in pub_keys:
|
||||||
sig_map[pk] = w
|
sig_map[pk] = w
|
||||||
break
|
break
|
||||||
@ -854,7 +852,7 @@ class Transaction(dict):
|
|||||||
assert "scriptPubKey" in self["vIn"][n]
|
assert "scriptPubKey" in self["vIn"][n]
|
||||||
script_code = self["vIn"][n]["scriptPubKey"]
|
script_code = self["vIn"][n]["scriptPubKey"]
|
||||||
if type(script_code) == str:
|
if type(script_code) == str:
|
||||||
script_code = unhexlify(script_code)
|
script_code = bytes.fromhex(script_code)
|
||||||
assert type(script_code) == bytes
|
assert type(script_code) == bytes
|
||||||
|
|
||||||
# remove opcode separators
|
# remove opcode separators
|
||||||
@ -902,7 +900,7 @@ class Transaction(dict):
|
|||||||
for i in self["vOut"]:
|
for i in self["vOut"]:
|
||||||
script_pub_key = self["vOut"][i]["scriptPubKey"]
|
script_pub_key = self["vOut"][i]["scriptPubKey"]
|
||||||
if type(self["vOut"][i]["scriptPubKey"]) == str:
|
if type(self["vOut"][i]["scriptPubKey"]) == str:
|
||||||
script_pub_key = unhexlify(script_pub_key)
|
script_pub_key = bytes.fromhex(script_pub_key)
|
||||||
if i > n and (sighash_type & 31) == SIGHASH_SINGLE:
|
if i > n and (sighash_type & 31) == SIGHASH_SINGLE:
|
||||||
continue
|
continue
|
||||||
if (sighash_type & 31) == SIGHASH_SINGLE and (n != i):
|
if (sighash_type & 31) == SIGHASH_SINGLE and (n != i):
|
||||||
@ -933,7 +931,7 @@ class Transaction(dict):
|
|||||||
assert "scriptPubKey" in self["vIn"][n]
|
assert "scriptPubKey" in self["vIn"][n]
|
||||||
script_code = self["vIn"][n]["scriptPubKey"]
|
script_code = self["vIn"][n]["scriptPubKey"]
|
||||||
if type(script_code) == str:
|
if type(script_code) == str:
|
||||||
script_code = unhexlify(script_code)
|
script_code = bytes.fromhex(script_code)
|
||||||
assert type(script_code) == bytes
|
assert type(script_code) == bytes
|
||||||
|
|
||||||
# remove opcode separators
|
# remove opcode separators
|
||||||
@ -967,7 +965,7 @@ class Transaction(dict):
|
|||||||
for o in self["vOut"]:
|
for o in self["vOut"]:
|
||||||
script_pub_key = self["vOut"][o]["scriptPubKey"]
|
script_pub_key = self["vOut"][o]["scriptPubKey"]
|
||||||
if type(self["vOut"][o]["scriptPubKey"]) == str:
|
if type(self["vOut"][o]["scriptPubKey"]) == str:
|
||||||
script_pub_key = unhexlify(script_pub_key)
|
script_pub_key = bytes.fromhex(script_pub_key)
|
||||||
if (sighash_type & 31) != SIGHASH_SINGLE and (sighash_type & 31) != SIGHASH_NONE:
|
if (sighash_type & 31) != SIGHASH_SINGLE and (sighash_type & 31) != SIGHASH_NONE:
|
||||||
ho += self["vOut"][o]["value"].to_bytes(8, 'little')
|
ho += self["vOut"][o]["value"].to_bytes(8, 'little')
|
||||||
ho += int_to_var_int(len(script_pub_key)) + script_pub_key
|
ho += int_to_var_int(len(script_pub_key)) + script_pub_key
|
||||||
@ -981,7 +979,7 @@ class Transaction(dict):
|
|||||||
preimage += struct.pack('<L', self["lockTime"])
|
preimage += struct.pack('<L', self["lockTime"])
|
||||||
preimage += struct.pack('<L', sighash_type)
|
preimage += struct.pack('<L', sighash_type)
|
||||||
sig_hash = double_sha256(preimage)
|
sig_hash = double_sha256(preimage)
|
||||||
return sig_hash if self["format"] == "raw" else hexlify(sig_hash).decode()
|
return sig_hash if self["format"] == "raw" else sig_hash.hex()
|
||||||
|
|
||||||
def __refresh__(self):
|
def __refresh__(self):
|
||||||
if not self["vOut"] or not self["vIn"]:
|
if not self["vOut"] or not self["vIn"]:
|
||||||
@ -1006,7 +1004,7 @@ class Transaction(dict):
|
|||||||
if self["format"] != "raw":
|
if self["format"] != "raw":
|
||||||
self["txId"] = rh2s(self["txId"])
|
self["txId"] = rh2s(self["txId"])
|
||||||
self["hash"] = rh2s(self["hash"])
|
self["hash"] = rh2s(self["hash"])
|
||||||
self["rawTx"] = hexlify(self["rawTx"]).decode()
|
self["rawTx"] = self["rawTx"].hex()
|
||||||
|
|
||||||
input_sum = 0
|
input_sum = 0
|
||||||
for i in self["vIn"]:
|
for i in self["vIn"]:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from .ecdsa import *
|
|||||||
from .transaction_deserialize import *
|
from .transaction_deserialize import *
|
||||||
from .transaction_constructor import *
|
from .transaction_constructor import *
|
||||||
from .sighash import *
|
from .sighash import *
|
||||||
|
from .block import *
|
||||||
|
|
||||||
# from .script_deserialize import *
|
# from .script_deserialize import *
|
||||||
# from .create_transaction import *
|
# from .create_transaction import *
|
||||||
from .block import *
|
|
||||||
@ -1,15 +1,16 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import os, sys
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
parentPath = os.path.abspath("..")
|
parentPath = os.path.abspath("..")
|
||||||
if parentPath not in sys.path:
|
if parentPath not in sys.path:
|
||||||
sys.path.insert(0, parentPath)
|
sys.path.insert(0, parentPath)
|
||||||
|
|
||||||
|
# from pybtc.transaction import *
|
||||||
from pybtc import address
|
|
||||||
from pybtc.transaction import *
|
|
||||||
from pybtc import OPCODE
|
from pybtc import OPCODE
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
import pybtc
|
||||||
|
|
||||||
class AddressClassTests(unittest.TestCase):
|
class AddressClassTests(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -18,33 +19,33 @@ class AddressClassTests(unittest.TestCase):
|
|||||||
|
|
||||||
def test_is_WIF_valid(self):
|
def test_is_WIF_valid(self):
|
||||||
# mainnet
|
# mainnet
|
||||||
self.assertEqual(address.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
|
self.assertEqual(pybtc.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
|
||||||
compressed=True, testnet=False).wif,
|
compressed=True, testnet=False).wif,
|
||||||
'L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4')
|
'L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4')
|
||||||
self.assertEqual(address.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
|
self.assertEqual(pybtc.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
|
||||||
compressed=False, testnet=False).wif,
|
compressed=False, testnet=False).wif,
|
||||||
'5Jkc7xqsrqA5pGQdwDHSQXRV3pUBLTXVjBjqJUSVz3pUmyuAFwP')
|
'5Jkc7xqsrqA5pGQdwDHSQXRV3pUBLTXVjBjqJUSVz3pUmyuAFwP')
|
||||||
# testnet
|
# testnet
|
||||||
self.assertEqual(address.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
|
self.assertEqual(pybtc.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
|
||||||
compressed=True, testnet=True).wif,
|
compressed=True, testnet=True).wif,
|
||||||
'cRiTUeUav1FMR4UbQh2gW9n8RfpNHLBHsEYXJYa4Rv6ZrCdTPGqv')
|
'cRiTUeUav1FMR4UbQh2gW9n8RfpNHLBHsEYXJYa4Rv6ZrCdTPGqv')
|
||||||
self.assertEqual(address.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
|
self.assertEqual(pybtc.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
|
||||||
compressed=False, testnet=True).wif,
|
compressed=False, testnet=True).wif,
|
||||||
'92XEhhfRT4EDnKuvZZBMH7yShUptVd4h58bnP6o1KnZXYzkVa55')
|
'92XEhhfRT4EDnKuvZZBMH7yShUptVd4h58bnP6o1KnZXYzkVa55')
|
||||||
|
|
||||||
self.assertEqual(address.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4",
|
self.assertEqual(pybtc.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4",
|
||||||
compressed=False, testnet=True).wif,
|
compressed=False, testnet=True).wif,
|
||||||
'L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4')
|
'L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4')
|
||||||
|
|
||||||
p = address.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4")
|
p = pybtc.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4")
|
||||||
pub = address.PublicKey(p)
|
pub = pybtc.PublicKey(p)
|
||||||
a = address.Address(p)
|
a = pybtc.Address(p)
|
||||||
self.assertEqual(a.address, 'bc1qxsms4rt5axt9674du2az7vq3pvephu3k5jyky8')
|
self.assertEqual(a.address, 'bc1qxsms4rt5axt9674du2az7vq3pvephu3k5jyky8')
|
||||||
a = address.Address(p, address_type = "P2PKH")
|
a = pybtc.Address(p, address_type = "P2PKH")
|
||||||
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
||||||
a = address.Address(p, address_type = "PUBKEY")
|
a = pybtc.Address(p, address_type = "PUBKEY")
|
||||||
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
||||||
a = address.Address(p, address_type = "P2SH_P2WPKH")
|
a = pybtc.Address(p, address_type = "P2SH_P2WPKH")
|
||||||
self.assertEqual(a.address, '37WJdFAoHDbxUQioDgtvPZuyJPyrrNQ7aL')
|
self.assertEqual(a.address, '37WJdFAoHDbxUQioDgtvPZuyJPyrrNQ7aL')
|
||||||
self.assertEqual(a.redeem_script_hex, '001434370a8d74e9965d7aade2ba2f30110b321bf236')
|
self.assertEqual(a.redeem_script_hex, '001434370a8d74e9965d7aade2ba2f30110b321bf236')
|
||||||
self.assertEqual(a.public_key.hex, '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
|
self.assertEqual(a.public_key.hex, '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
|
||||||
@ -53,58 +54,58 @@ class AddressClassTests(unittest.TestCase):
|
|||||||
ucpk = "04a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb" \
|
ucpk = "04a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb" \
|
||||||
"43bbd96a641808e5f34eb568e804fe679de82de419e2512736ea09013a82324a6"
|
"43bbd96a641808e5f34eb568e804fe679de82de419e2512736ea09013a82324a6"
|
||||||
# public key uncompressed from HEX private
|
# public key uncompressed from HEX private
|
||||||
self.assertEqual(address.PublicKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76",
|
self.assertEqual(pybtc.PublicKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76",
|
||||||
compressed=False).hex, ucpk)
|
compressed=False).hex, ucpk)
|
||||||
# public key compressed from HEX private
|
# public key compressed from HEX private
|
||||||
self.assertEqual(address.PublicKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76",
|
self.assertEqual(pybtc.PublicKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76",
|
||||||
compressed=True).hex, cpk)
|
compressed=True).hex, cpk)
|
||||||
# public key compressed from WIF private
|
# public key compressed from WIF private
|
||||||
self.assertEqual(address.PublicKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4",
|
self.assertEqual(pybtc.PublicKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4",
|
||||||
compressed=False).hex, cpk)
|
compressed=False).hex, cpk)
|
||||||
# public key compressed from PrivateKey instance (flags have no effect)
|
# public key compressed from PrivateKey instance (flags have no effect)
|
||||||
p = address.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4")
|
p = pybtc.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4")
|
||||||
self.assertEqual(address.PublicKey(p, compressed=False).hex, cpk)
|
self.assertEqual(pybtc.PublicKey(p, compressed=False).hex, cpk)
|
||||||
|
|
||||||
# public key compressed from public
|
# public key compressed from public
|
||||||
self.assertEqual(address.PublicKey(cpk, compressed=False).hex, cpk)
|
self.assertEqual(pybtc.PublicKey(cpk, compressed=False).hex, cpk)
|
||||||
|
|
||||||
# public key compressed from public
|
# public key compressed from public
|
||||||
self.assertEqual(address.PublicKey(unhexlify(cpk), compressed=False).hex, cpk)
|
self.assertEqual(pybtc.PublicKey(unhexlify(cpk), compressed=False).hex, cpk)
|
||||||
|
|
||||||
# compressed public key
|
# compressed public key
|
||||||
# private key hex string to compressed pub key
|
# private key hex string to compressed pub key
|
||||||
p = address.PrivateKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76", compressed=False)
|
p = pybtc.PrivateKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76", compressed=False)
|
||||||
pub = address.PublicKey(p)
|
pub = pybtc.PublicKey(p)
|
||||||
a = address.Address(p, address_type="P2PKH")
|
a = pybtc.Address(p, address_type="P2PKH")
|
||||||
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
||||||
a = address.Address(p, address_type="PUBKEY")
|
a = pybtc.Address(p, address_type="PUBKEY")
|
||||||
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
||||||
|
|
||||||
# from pubkey
|
# from pubkey
|
||||||
p = address.PublicKey('02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
|
p = pybtc.PublicKey('02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
|
||||||
a = address.Address(p)
|
a = pybtc.Address(p)
|
||||||
self.assertEqual(a.address, 'bc1qxsms4rt5axt9674du2az7vq3pvephu3k5jyky8')
|
self.assertEqual(a.address, 'bc1qxsms4rt5axt9674du2az7vq3pvephu3k5jyky8')
|
||||||
a = address.Address(p, address_type="P2PKH")
|
a = pybtc.Address(p, address_type="P2PKH")
|
||||||
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
||||||
a = address.Address(p, address_type="PUBKEY")
|
a = pybtc.Address(p, address_type="PUBKEY")
|
||||||
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
||||||
a = address.Address(p, address_type="P2SH_P2WPKH")
|
a = pybtc.Address(p, address_type="P2SH_P2WPKH")
|
||||||
self.assertEqual(a.address, '37WJdFAoHDbxUQioDgtvPZuyJPyrrNQ7aL')
|
self.assertEqual(a.address, '37WJdFAoHDbxUQioDgtvPZuyJPyrrNQ7aL')
|
||||||
self.assertEqual(a.redeem_script_hex, '001434370a8d74e9965d7aade2ba2f30110b321bf236')
|
self.assertEqual(a.redeem_script_hex, '001434370a8d74e9965d7aade2ba2f30110b321bf236')
|
||||||
self.assertEqual(a.public_key.hex, '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
|
self.assertEqual(a.public_key.hex, '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
|
||||||
|
|
||||||
# from uncompressed pubkey
|
# from uncompressed pubkey
|
||||||
p = address.PublicKey('04a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb43bbd96a641808'
|
p = pybtc.PublicKey('04a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb43bbd96a641808'
|
||||||
'e5f34eb568e804fe679de82de419e2512736ea09013a82324a6')
|
'e5f34eb568e804fe679de82de419e2512736ea09013a82324a6')
|
||||||
a = address.Address(p, address_type="P2PKH")
|
a = pybtc.Address(p, address_type="P2PKH")
|
||||||
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
||||||
a = address.Address(p, address_type="PUBKEY")
|
a = pybtc.Address(p, address_type="PUBKEY")
|
||||||
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
||||||
|
|
||||||
redeem = "5221032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b2" \
|
redeem = "5221032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b2" \
|
||||||
"6473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b26473e2967b8fd403b4b544b8" \
|
"6473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b26473e2967b8fd403b4b544b8" \
|
||||||
"36e71abdfebb08d8c96d6953ae"
|
"36e71abdfebb08d8c96d6953ae"
|
||||||
a = address.ScriptAddress(redeem, witness_version=None)
|
a = pybtc.ScriptAddress(redeem, witness_version=None)
|
||||||
self.assertEqual(a.address, '3KCqqS6eznp3ucVPxtNkiYcVg6kQKNX9sg')
|
self.assertEqual(a.address, '3KCqqS6eznp3ucVPxtNkiYcVg6kQKNX9sg')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,8 @@ parentPath = os.path.abspath("..")
|
|||||||
if parentPath not in sys.path:
|
if parentPath not in sys.path:
|
||||||
sys.path.insert(0, parentPath)
|
sys.path.insert(0, parentPath)
|
||||||
|
|
||||||
from pybtc import tools
|
from pybtc.functions import script as tools
|
||||||
|
from pybtc import functions
|
||||||
from pybtc import BYTE_OPCODE, HEX_OPCODE
|
from pybtc import BYTE_OPCODE, HEX_OPCODE
|
||||||
from binascii import unhexlify, hexlify
|
from binascii import unhexlify, hexlify
|
||||||
|
|
||||||
@ -20,36 +21,36 @@ class AddressFunctionsTests(unittest.TestCase):
|
|||||||
pum = "5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"
|
pum = "5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"
|
||||||
put = "93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L"
|
put = "93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L"
|
||||||
pct = "cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"
|
pct = "cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"
|
||||||
self.assertEqual(tools.private_key_to_wif(p, compressed=1, testnet=0), pcm)
|
self.assertEqual(functions.private_key_to_wif(p, compressed=1, testnet=0), pcm)
|
||||||
self.assertEqual(tools.private_key_to_wif(p, compressed=0, testnet=0), pum)
|
self.assertEqual(functions.private_key_to_wif(p, compressed=0, testnet=0), pum)
|
||||||
self.assertEqual(tools.private_key_to_wif(p, compressed=1, testnet=1), pct)
|
self.assertEqual(functions.private_key_to_wif(p, compressed=1, testnet=1), pct)
|
||||||
self.assertEqual(tools.private_key_to_wif(p, compressed=0, testnet=1), put)
|
self.assertEqual(functions.private_key_to_wif(p, compressed=0, testnet=1), put)
|
||||||
|
|
||||||
def test_is_WIF_valid(self):
|
def test_is_WIF_valid(self):
|
||||||
self.assertEqual(tools.is_wif_valid("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX"), 1)
|
self.assertEqual(functions.is_wif_valid("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX"), 1)
|
||||||
self.assertEqual(tools.is_wif_valid("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"), 1)
|
self.assertEqual(functions.is_wif_valid("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"), 1)
|
||||||
self.assertEqual(tools.is_wif_valid("5KPPLXhtga99qqMcWRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"), 0)
|
self.assertEqual(functions.is_wif_valid("5KPPLXhtga99qqMcWRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"), 0)
|
||||||
self.assertEqual(tools.is_wif_valid("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L"), 1)
|
self.assertEqual(functions.is_wif_valid("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L"), 1)
|
||||||
self.assertEqual(tools.is_wif_valid("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"), 1)
|
self.assertEqual(functions.is_wif_valid("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"), 1)
|
||||||
self.assertEqual(tools.is_wif_valid("cUWo47XLYiyByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"), 0)
|
self.assertEqual(functions.is_wif_valid("cUWo47XLYiyByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"), 0)
|
||||||
|
|
||||||
def test_WIF_to_private_key(self):
|
def test_WIF_to_private_key(self):
|
||||||
p = "ceda1ae4286015d45ec5147fe3f63e9377ccd6d4e98bcf0847df9937da1944a4"
|
p = "ceda1ae4286015d45ec5147fe3f63e9377ccd6d4e98bcf0847df9937da1944a4"
|
||||||
self.assertEqual(tools.wif_to_private_key("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX",
|
self.assertEqual(functions.wif_to_private_key("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX",
|
||||||
hex=1),p)
|
hex=1),p)
|
||||||
self.assertEqual(tools.wif_to_private_key("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX",
|
self.assertEqual(functions.wif_to_private_key("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX",
|
||||||
hex=0),unhexlify(p))
|
hex=0),unhexlify(p))
|
||||||
self.assertEqual(tools.wif_to_private_key("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf",
|
self.assertEqual(functions.wif_to_private_key("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf",
|
||||||
hex=1),p)
|
hex=1),p)
|
||||||
self.assertEqual(tools.wif_to_private_key("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L",
|
self.assertEqual(functions.wif_to_private_key("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L",
|
||||||
hex=1),p)
|
hex=1),p)
|
||||||
self.assertEqual(tools.wif_to_private_key("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6",
|
self.assertEqual(functions.wif_to_private_key("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6",
|
||||||
hex=1),p)
|
hex=1),p)
|
||||||
|
|
||||||
def test_create_private_key(self):
|
def test_create_private_key(self):
|
||||||
p = tools.create_private_key(wif=0)
|
p = functions.create_private_key(wif=0)
|
||||||
pw = tools.private_key_to_wif(p)
|
pw = functions.private_key_to_wif(p)
|
||||||
self.assertEqual(tools.is_wif_valid(pw), True)
|
self.assertEqual(functions.is_wif_valid(pw), True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -57,158 +58,158 @@ class AddressFunctionsTests(unittest.TestCase):
|
|||||||
p = "ceda1ae4286015d45ec5147fe3f63e9377ccd6d4e98bcf0847df9937da1944a4"
|
p = "ceda1ae4286015d45ec5147fe3f63e9377ccd6d4e98bcf0847df9937da1944a4"
|
||||||
pu = "04b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4c8cbe28702911260f2a1da099a338bed4ee98f66bb8dba8031a76ab537ff6663"
|
pu = "04b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4c8cbe28702911260f2a1da099a338bed4ee98f66bb8dba8031a76ab537ff6663"
|
||||||
pk = "03b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4"
|
pk = "03b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4"
|
||||||
self.assertEqual(tools.private_to_public_key(p, hex=1), pk)
|
self.assertEqual(functions.private_to_public_key(p, hex=1), pk)
|
||||||
self.assertEqual(tools.private_to_public_key(p, hex=0), unhexlify(pk))
|
self.assertEqual(functions.private_to_public_key(p, hex=0), unhexlify(pk))
|
||||||
self.assertEqual(tools.private_to_public_key(p, compressed=0, hex=1), pu)
|
self.assertEqual(functions.private_to_public_key(p, compressed=0, hex=1), pu)
|
||||||
self.assertEqual(tools.private_to_public_key("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX", hex=1), pk)
|
self.assertEqual(functions.private_to_public_key("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX", hex=1), pk)
|
||||||
self.assertEqual(tools.private_to_public_key("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf", hex=1), pu)
|
self.assertEqual(functions.private_to_public_key("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf", hex=1), pu)
|
||||||
self.assertEqual(tools.private_to_public_key("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L", hex=1), pu)
|
self.assertEqual(functions.private_to_public_key("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L", hex=1), pu)
|
||||||
self.assertEqual(tools.private_to_public_key("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6", hex=1), pk)
|
self.assertEqual(functions.private_to_public_key("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6", hex=1), pk)
|
||||||
|
|
||||||
def test_hash_to_address(self):
|
def test_hash_to_address(self):
|
||||||
pc = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
|
pc = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
|
||||||
h = tools.hash160(pc)
|
h = tools.hash160(pc)
|
||||||
s = bytes([len(unhexlify(pc))])+unhexlify(pc) + BYTE_OPCODE["OP_CHECKSIG"]
|
s = bytes([len(unhexlify(pc))])+unhexlify(pc) + BYTE_OPCODE["OP_CHECKSIG"]
|
||||||
self.assertEqual(tools.hash_to_address(h), "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
self.assertEqual(functions.hash_to_address(h), "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
||||||
self.assertEqual(tools.hash_to_address(h, testnet=1), "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx")
|
self.assertEqual(functions.hash_to_address(h, testnet=1), "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx")
|
||||||
h = tools.script_to_hash(s, 1, 1)
|
h = tools.script_to_hash(s, 1, 1)
|
||||||
self.assertEqual(tools.hash_to_address(h), "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3")
|
self.assertEqual(functions.hash_to_address(h), "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3")
|
||||||
self.assertEqual(tools.hash_to_address(h, testnet=1), "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7")
|
self.assertEqual(functions.hash_to_address(h, testnet=1), "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7")
|
||||||
pk = "03b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4"
|
pk = "03b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4"
|
||||||
h = tools.hash160(pk)
|
h = tools.hash160(pk)
|
||||||
self.assertEqual(tools.hash_to_address(h, witness_version=None), "1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1")
|
self.assertEqual(functions.hash_to_address(h, witness_version=None), "1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1")
|
||||||
self.assertEqual(tools.hash_to_address(h, witness_version=None, testnet=1),
|
self.assertEqual(functions.hash_to_address(h, witness_version=None, testnet=1),
|
||||||
"mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
"mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
||||||
# p2wpkh inside p2sh
|
# p2wpkh inside p2sh
|
||||||
p = "L32a8Mo1LgvjrVDbzcc3NkuUfkpoLsf2Y2oEWkV4t1KpQdFzuyff"
|
p = "L32a8Mo1LgvjrVDbzcc3NkuUfkpoLsf2Y2oEWkV4t1KpQdFzuyff"
|
||||||
pk = tools.private_to_public_key(p)
|
pk = functions.private_to_public_key(p)
|
||||||
script = b'\x00\x14' + tools.hash160(pk)
|
script = b'\x00\x14' + tools.hash160(pk)
|
||||||
script_hash = tools.hash160(script)
|
script_hash = tools.hash160(script)
|
||||||
self.assertEqual(tools.hash_to_address(script_hash,
|
self.assertEqual(functions.hash_to_address(script_hash,
|
||||||
script_hash=1,
|
script_hash=1,
|
||||||
witness_version=None), "33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw")
|
witness_version=None), "33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw")
|
||||||
self.assertEqual(tools.hash_to_address(script_hash,
|
self.assertEqual(functions.hash_to_address(script_hash,
|
||||||
script_hash=1,
|
script_hash=1,
|
||||||
witness_version=None,
|
witness_version=None,
|
||||||
testnet=1), "2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh")
|
testnet=1), "2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh")
|
||||||
|
|
||||||
def test_address_to_hash(self):
|
def test_address_to_hash(self):
|
||||||
h = "751e76e8199196d454941c45d1b3a323f1433bd6"
|
h = "751e76e8199196d454941c45d1b3a323f1433bd6"
|
||||||
self.assertEqual(tools.address_to_hash("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1), h)
|
self.assertEqual(functions.address_to_hash("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1), h)
|
||||||
self.assertEqual(tools.address_to_hash("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx", 1), h)
|
self.assertEqual(functions.address_to_hash("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx", 1), h)
|
||||||
h = "1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"
|
h = "1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"
|
||||||
self.assertEqual(tools.address_to_hash("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", 1), h)
|
self.assertEqual(functions.address_to_hash("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", 1), h)
|
||||||
h = "a307d67484911deee457779b17505cedd20e1fe9"
|
h = "a307d67484911deee457779b17505cedd20e1fe9"
|
||||||
self.assertEqual(tools.address_to_hash("1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1", 1), h)
|
self.assertEqual(functions.address_to_hash("1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1", 1), h)
|
||||||
self.assertEqual(tools.address_to_hash("mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c", 1), h)
|
self.assertEqual(functions.address_to_hash("mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c", 1), h)
|
||||||
h = "14c14c8d26acbea970757b78e6429ad05a6ac6bb"
|
h = "14c14c8d26acbea970757b78e6429ad05a6ac6bb"
|
||||||
self.assertEqual(tools.address_to_hash("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw", 1), h)
|
self.assertEqual(functions.address_to_hash("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw", 1), h)
|
||||||
self.assertEqual(tools.address_to_hash("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh", 1), h)
|
self.assertEqual(functions.address_to_hash("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh", 1), h)
|
||||||
|
|
||||||
def test_address_type(self):
|
def test_address_type(self):
|
||||||
self.assertEqual(tools.address_type("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), 'P2WPKH')
|
self.assertEqual(functions.address_type("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), 'P2WPKH')
|
||||||
self.assertEqual(tools.address_type("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"), 'P2WPKH')
|
self.assertEqual(functions.address_type("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"), 'P2WPKH')
|
||||||
self.assertEqual(tools.address_type("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3"), 'P2WSH')
|
self.assertEqual(functions.address_type("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3"), 'P2WSH')
|
||||||
self.assertEqual(tools.address_type("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7"), 'P2WSH')
|
self.assertEqual(functions.address_type("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7"), 'P2WSH')
|
||||||
self.assertEqual(tools.address_type("1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1"), 'P2PKH')
|
self.assertEqual(functions.address_type("1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1"), 'P2PKH')
|
||||||
self.assertEqual(tools.address_type("mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c"), 'P2PKH')
|
self.assertEqual(functions.address_type("mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c"), 'P2PKH')
|
||||||
self.assertEqual(tools.address_type("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw"), 'P2SH')
|
self.assertEqual(functions.address_type("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw"), 'P2SH')
|
||||||
self.assertEqual(tools.address_type("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh"), 'P2SH')
|
self.assertEqual(functions.address_type("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh"), 'P2SH')
|
||||||
|
|
||||||
def test_address_net_type(self):
|
def test_address_net_type(self):
|
||||||
self.assertEqual(tools.address_net_type("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), 'mainnet')
|
self.assertEqual(functions.address_net_type("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), 'mainnet')
|
||||||
self.assertEqual(tools.address_net_type("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"), 'testnet')
|
self.assertEqual(functions.address_net_type("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"), 'testnet')
|
||||||
self.assertEqual(tools.address_net_type("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3"),
|
self.assertEqual(functions.address_net_type("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3"),
|
||||||
'mainnet')
|
'mainnet')
|
||||||
self.assertEqual(tools.address_net_type("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7"),
|
self.assertEqual(functions.address_net_type("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7"),
|
||||||
'testnet')
|
'testnet')
|
||||||
self.assertEqual(tools.address_net_type("1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1"), 'mainnet')
|
self.assertEqual(functions.address_net_type("1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1"), 'mainnet')
|
||||||
self.assertEqual(tools.address_net_type("mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c"), 'testnet')
|
self.assertEqual(functions.address_net_type("mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c"), 'testnet')
|
||||||
self.assertEqual(tools.address_net_type("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw"), 'mainnet')
|
self.assertEqual(functions.address_net_type("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw"), 'mainnet')
|
||||||
self.assertEqual(tools.address_net_type("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh"), 'testnet')
|
self.assertEqual(functions.address_net_type("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh"), 'testnet')
|
||||||
|
|
||||||
def test_public_key_to_address(self):
|
def test_public_key_to_address(self):
|
||||||
pc = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
|
pc = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
|
||||||
self.assertEqual(tools.public_key_to_address(pc), "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
self.assertEqual(functions.public_key_to_address(pc), "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
||||||
self.assertEqual(tools.public_key_to_address(pc, testnet=1), "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx")
|
self.assertEqual(functions.public_key_to_address(pc, testnet=1), "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx")
|
||||||
pc = "03b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4"
|
pc = "03b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4"
|
||||||
self.assertEqual(tools.public_key_to_address(pc,
|
self.assertEqual(functions.public_key_to_address(pc,
|
||||||
witness_version=None,
|
witness_version=None,
|
||||||
testnet=0), "1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1")
|
testnet=0), "1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1")
|
||||||
self.assertEqual(tools.public_key_to_address(pc, witness_version=None,
|
self.assertEqual(functions.public_key_to_address(pc, witness_version=None,
|
||||||
testnet=1), "mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
testnet=1), "mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
||||||
p = "L32a8Mo1LgvjrVDbzcc3NkuUfkpoLsf2Y2oEWkV4t1KpQdFzuyff"
|
p = "L32a8Mo1LgvjrVDbzcc3NkuUfkpoLsf2Y2oEWkV4t1KpQdFzuyff"
|
||||||
pk = tools.private_to_public_key(p)
|
pk = functions.private_to_public_key(p)
|
||||||
self.assertEqual(tools.public_key_to_address(pk, p2sh_p2wpkh=1,
|
self.assertEqual(functions.public_key_to_address(pk, p2sh_p2wpkh=1,
|
||||||
witness_version=None), "33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw")
|
witness_version=None), "33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw")
|
||||||
|
|
||||||
def test_is_address_valid(self):
|
def test_is_address_valid(self):
|
||||||
self.assertEqual(tools.is_address_valid("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), 1)
|
self.assertEqual(functions.is_address_valid("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), 1)
|
||||||
self.assertEqual(tools.is_address_valid("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx", 1), 1)
|
self.assertEqual(functions.is_address_valid("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx", 1), 1)
|
||||||
self.assertEqual(tools.is_address_valid("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"), 0)
|
self.assertEqual(functions.is_address_valid("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"), 0)
|
||||||
self.assertEqual(tools.is_address_valid("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3"), 1)
|
self.assertEqual(functions.is_address_valid("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3"), 1)
|
||||||
self.assertEqual(tools.is_address_valid("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", 1), 1)
|
self.assertEqual(functions.is_address_valid("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", 1), 1)
|
||||||
self.assertEqual(tools.is_address_valid("1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1"), 1)
|
self.assertEqual(functions.is_address_valid("1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1"), 1)
|
||||||
self.assertEqual(tools.is_address_valid("mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c", 1), 1)
|
self.assertEqual(functions.is_address_valid("mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c", 1), 1)
|
||||||
self.assertEqual(tools.is_address_valid("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw"), 1)
|
self.assertEqual(functions.is_address_valid("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw"), 1)
|
||||||
self.assertEqual(tools.is_address_valid("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh",1), 1)
|
self.assertEqual(functions.is_address_valid("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh",1), 1)
|
||||||
self.assertEqual(tools.is_address_valid("2Mu8y4mm4oF89yppDbUAAEwyBEPezrx7CLh",1), 0)
|
self.assertEqual(functions.is_address_valid("2Mu8y4mm4oF89yppDbUAAEwyBEPezrx7CLh",1), 0)
|
||||||
self.assertEqual(tools.is_address_valid("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1), 0)
|
self.assertEqual(functions.is_address_valid("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1), 0)
|
||||||
self.assertEqual(tools.is_address_valid("tb1qw508d6qejxtdg4W5r3zarvary0c5xw7kxpjzsx",1), 0)
|
self.assertEqual(functions.is_address_valid("tb1qw508d6qejxtdg4W5r3zarvary0c5xw7kxpjzsx",1), 0)
|
||||||
self.assertEqual(tools.is_address_valid("bc1qrp33g0q5c5txsp8arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3"), 0)
|
self.assertEqual(functions.is_address_valid("bc1qrp33g0q5c5txsp8arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3"), 0)
|
||||||
self.assertEqual(tools.is_address_valid("tb1qrp23g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",1), 0)
|
self.assertEqual(functions.is_address_valid("tb1qrp23g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",1), 0)
|
||||||
self.assertEqual(tools.is_address_valid("1Fs2Xqrk4P2XADaJeZWykaGXJ2HEb6RyT1"), 0)
|
self.assertEqual(functions.is_address_valid("1Fs2Xqrk4P2XADaJeZWykaGXJ2HEb6RyT1"), 0)
|
||||||
self.assertEqual(tools.is_address_valid("mvNyptwisQTkwL3vN8VMaVUrA3swVCX83c", 1), 0)
|
self.assertEqual(functions.is_address_valid("mvNyptwisQTkwL3vN8VMaVUrA3swVCX83c", 1), 0)
|
||||||
self.assertEqual(tools.is_address_valid("33am12q3Bncmn3BfvLYHczyv23Sq2Wbwjw"), 0)
|
self.assertEqual(functions.is_address_valid("33am12q3Bncmn3BfvLYHczyv23Sq2Wbwjw"), 0)
|
||||||
self.assertEqual(tools.is_address_valid("2Mu8y4mm4oF78yppDbUAAEwyBEPezrx7CLh", 1), 0)
|
self.assertEqual(functions.is_address_valid("2Mu8y4mm4oF78yppDbUAAEwyBEPezrx7CLh", 1), 0)
|
||||||
|
|
||||||
def test_address_to_script(self):
|
def test_address_to_script(self):
|
||||||
self.assertEqual(tools.address_to_script("17rPqUf4Hqu6Lvpgfsavt1CzRy2GL19GD3", 1),
|
self.assertEqual(functions.address_to_script("17rPqUf4Hqu6Lvpgfsavt1CzRy2GL19GD3", 1),
|
||||||
"76a9144b2832feeda5692c96c0594a6314136a998f515788ac")
|
"76a9144b2832feeda5692c96c0594a6314136a998f515788ac")
|
||||||
self.assertEqual(tools.address_to_script("33RYUa9jT541UNPsKdV7V1DmwMiQHpVfD3", 1),
|
self.assertEqual(functions.address_to_script("33RYUa9jT541UNPsKdV7V1DmwMiQHpVfD3", 1),
|
||||||
"a914130319921ecbcfa33fec2a8503c4ae1c86e4419387")
|
"a914130319921ecbcfa33fec2a8503c4ae1c86e4419387")
|
||||||
self.assertEqual(tools.address_to_script("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1),
|
self.assertEqual(functions.address_to_script("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1),
|
||||||
"0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
"0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
||||||
self.assertEqual(tools.address_to_script("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1),
|
self.assertEqual(functions.address_to_script("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1),
|
||||||
"0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
"0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
||||||
|
|
||||||
def test_parse_script(self):
|
def test_parse_script(self):
|
||||||
|
|
||||||
k = tools.parse_script("76a9144b2832feeda5692c96c0594a6314136a998f515788ac")
|
k = tools.parse_script("76a9144b2832feeda5692c96c0594a6314136a998f515788ac")
|
||||||
address = tools.hash_to_address(k["addressHash"], witness_version = None)
|
address = functions.hash_to_address(k["addressHash"], witness_version = None)
|
||||||
self.assertEqual(address, "17rPqUf4Hqu6Lvpgfsavt1CzRy2GL19GD3")
|
self.assertEqual(address, "17rPqUf4Hqu6Lvpgfsavt1CzRy2GL19GD3")
|
||||||
self.assertEqual(k["type"],"P2PKH")
|
self.assertEqual(k["type"],"P2PKH")
|
||||||
self.assertEqual(k["nType"],0)
|
self.assertEqual(k["nType"],0)
|
||||||
self.assertEqual(k["reqSigs"],1)
|
self.assertEqual(k["reqSigs"],1)
|
||||||
self.assertEqual(tools.address_to_script(address, 1),
|
self.assertEqual(functions.address_to_script(address, 1),
|
||||||
"76a9144b2832feeda5692c96c0594a6314136a998f515788ac")
|
"76a9144b2832feeda5692c96c0594a6314136a998f515788ac")
|
||||||
|
|
||||||
k = tools.parse_script("76a914a307d67484911deee457779b17505cedd20e1fe988ac")
|
k = tools.parse_script("76a914a307d67484911deee457779b17505cedd20e1fe988ac")
|
||||||
address = tools.hash_to_address(k["addressHash"],testnet= True, witness_version = None)
|
address = functions.hash_to_address(k["addressHash"], testnet= True, witness_version=None)
|
||||||
self.assertEqual(address,"mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
self.assertEqual(address,"mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
||||||
self.assertEqual(k["type"],"P2PKH")
|
self.assertEqual(k["type"],"P2PKH")
|
||||||
self.assertEqual(k["nType"],0)
|
self.assertEqual(k["nType"],0)
|
||||||
self.assertEqual(k["reqSigs"],1)
|
self.assertEqual(k["reqSigs"],1)
|
||||||
self.assertEqual(tools.address_to_script(address, 1),
|
self.assertEqual(functions.address_to_script(address, 1),
|
||||||
"76a914a307d67484911deee457779b17505cedd20e1fe988ac")
|
"76a914a307d67484911deee457779b17505cedd20e1fe988ac")
|
||||||
|
|
||||||
k = tools.parse_script("a914b316ac9bdd0816ecdec6773d1192c0eaf52ae66487")
|
k = tools.parse_script("a914b316ac9bdd0816ecdec6773d1192c0eaf52ae66487")
|
||||||
address = tools.hash_to_address(k["addressHash"],script_hash = True ,witness_version = None)
|
address = functions.hash_to_address(k["addressHash"], script_hash=True, witness_version=None)
|
||||||
self.assertEqual(address, "3J1x3KHjgjoTjqHjrwKax2zeT8LSDkZJae")
|
self.assertEqual(address, "3J1x3KHjgjoTjqHjrwKax2zeT8LSDkZJae")
|
||||||
self.assertEqual(k["type"],"P2SH")
|
self.assertEqual(k["type"],"P2SH")
|
||||||
self.assertEqual(k["nType"],1)
|
self.assertEqual(k["nType"],1)
|
||||||
self.assertEqual(k["reqSigs"], None)
|
self.assertEqual(k["reqSigs"], None)
|
||||||
self.assertEqual(tools.address_to_script(address, 1),
|
self.assertEqual(functions.address_to_script(address, 1),
|
||||||
"a914b316ac9bdd0816ecdec6773d1192c0eaf52ae66487")
|
"a914b316ac9bdd0816ecdec6773d1192c0eaf52ae66487")
|
||||||
|
|
||||||
k = tools.parse_script("0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
k = tools.parse_script("0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
||||||
address = tools.hash_to_address(k["addressHash"],script_hash = False,
|
address = functions.hash_to_address(k["addressHash"], script_hash=False,
|
||||||
witness_version = 0, testnet = False)
|
witness_version=0, testnet=False)
|
||||||
self.assertEqual(address, "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
self.assertEqual(address, "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
||||||
self.assertEqual(k["type"],"P2WPKH")
|
self.assertEqual(k["type"],"P2WPKH")
|
||||||
self.assertEqual(k["nType"],5)
|
self.assertEqual(k["nType"],5)
|
||||||
self.assertEqual(k["reqSigs"],1)
|
self.assertEqual(k["reqSigs"],1)
|
||||||
self.assertEqual(tools.address_to_script(address, 1),
|
self.assertEqual(functions.address_to_script(address, 1),
|
||||||
"0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
"0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
||||||
|
|
||||||
s = [HEX_OPCODE['OP_HASH160'],
|
s = [HEX_OPCODE['OP_HASH160'],
|
||||||
@ -218,13 +219,13 @@ class AddressFunctionsTests(unittest.TestCase):
|
|||||||
h = ''.join(s)
|
h = ''.join(s)
|
||||||
s = unhexlify(h)
|
s = unhexlify(h)
|
||||||
k = tools.parse_script(s)
|
k = tools.parse_script(s)
|
||||||
address = tools.hash_to_address(k["addressHash"],script_hash = True,
|
address = functions.hash_to_address(k["addressHash"], script_hash=True,
|
||||||
witness_version = None, testnet = False)
|
witness_version=None, testnet=False)
|
||||||
self.assertEqual(address, "3F527pX8o2pgr6FuNdNvngA2Do2wVvDoZi")
|
self.assertEqual(address, "3F527pX8o2pgr6FuNdNvngA2Do2wVvDoZi")
|
||||||
self.assertEqual(k["type"],"P2SH")
|
self.assertEqual(k["type"],"P2SH")
|
||||||
self.assertEqual(k["nType"],1)
|
self.assertEqual(k["nType"],1)
|
||||||
self.assertEqual(k["reqSigs"], None)
|
self.assertEqual(k["reqSigs"], None)
|
||||||
self.assertEqual(tools.address_to_script(address, 1), h)
|
self.assertEqual(functions.address_to_script(address, 1), h)
|
||||||
|
|
||||||
s = [HEX_OPCODE['OP_3'],
|
s = [HEX_OPCODE['OP_3'],
|
||||||
'21',
|
'21',
|
||||||
@ -245,8 +246,8 @@ class AddressFunctionsTests(unittest.TestCase):
|
|||||||
s = unhexlify(h)
|
s = unhexlify(h)
|
||||||
k = tools.parse_script(s)
|
k = tools.parse_script(s)
|
||||||
sh = tools.script_to_hash(h, 0, 0)
|
sh = tools.script_to_hash(h, 0, 0)
|
||||||
address = tools.hash_to_address(sh,script_hash = True,
|
address = functions.hash_to_address(sh,script_hash=True,
|
||||||
witness_version = None, testnet = False)
|
witness_version=None, testnet=False)
|
||||||
self.assertEqual(address, "3D2oetdNuZUqQHPJmcMDDHYoqkyNVsFk9r")
|
self.assertEqual(address, "3D2oetdNuZUqQHPJmcMDDHYoqkyNVsFk9r")
|
||||||
self.assertEqual(k["type"],"MULTISIG")
|
self.assertEqual(k["type"],"MULTISIG")
|
||||||
self.assertEqual(k["nType"],4)
|
self.assertEqual(k["nType"],4)
|
||||||
|
|||||||
@ -4,7 +4,7 @@ parentPath = os.path.abspath("..")
|
|||||||
if parentPath not in sys.path:
|
if parentPath not in sys.path:
|
||||||
sys.path.insert(0, parentPath)
|
sys.path.insert(0, parentPath)
|
||||||
|
|
||||||
from pybtc import block
|
from pybtc import *
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
from pybtc import rh2s
|
from pybtc import rh2s
|
||||||
from pybtc import *
|
from pybtc import *
|
||||||
@ -596,13 +596,19 @@ class BlockDeserializeTests(unittest.TestCase):
|
|||||||
def test_block_class(self):
|
def test_block_class(self):
|
||||||
block_c = "2000000000000000000029a1a0390376afd72db120d698c2d8ebc41c545c7d4bc2b9033c303dd3d09d455da1c587406820a4dd77c5aa3fcc546dcceb1becc639829c4fe6535e815a1a372b405cc0829701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2303f88e130068747470733a5c6170692e6269746170732e636f6d20f251bec0cb000000ffffffff02c817a804000000001976a914d4e49947b9f545218cd20389244c249d3520545d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"
|
block_c = "2000000000000000000029a1a0390376afd72db120d698c2d8ebc41c545c7d4bc2b9033c303dd3d09d455da1c587406820a4dd77c5aa3fcc546dcceb1becc639829c4fe6535e815a1a372b405cc0829701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2303f88e130068747470733a5c6170692e6269746170732e636f6d20f251bec0cb000000ffffffff02c817a804000000001976a914d4e49947b9f545218cd20389244c249d3520545d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
block_e = "2000000000000000000029a1a0390376afd72db120d698c2d8ebc41c545c7d4bc2b9033c303dd3d09d455da1c587406820a4dd77c5aa3fcc546dcceb1becc639829c4fe65a815e531a372b405cc0829701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2303f88e130068747470733a5c6170692e6269746170732e636f6d20f251bec0cb000000ffffffff02c817a804000000001976a914d4e49947b9f545218cd20389244c249d3520545d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"
|
block_e = "2000000000000000000029a1a0390376afd72db120d698c2d8ebc41c545c7d4bc2b9033c303dd3d09d455da1c587406820a4dd77c5aa3fcc546dcceb1becc639829c4fe65a815e531a372b405cc0829701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2303f88e130068747470733a5c6170692e6269746170732e636f6d20f251bec0cb000000ffffffff02c817a804000000001976a914d4e49947b9f545218cd20389244c249d3520545d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
l = block.Block(block_a, format="decoded")
|
l = Block(block_a, format="decoded")
|
||||||
f = open('./test/raw_block.txt')
|
f = open('./test/raw_block.txt')
|
||||||
fc = f.readline()
|
fc = f.readline()
|
||||||
qt = time.time()
|
qt = time.time()
|
||||||
bt = block.Block(fc[:-1], format="decoded")
|
bt = Block(fc[:-1], format="decoded")
|
||||||
# self.assertEqual(time.time() - qt < 1, 1)
|
print("decoded block", time.time() - qt )
|
||||||
|
|
||||||
|
import cProfile
|
||||||
|
|
||||||
|
cProfile.run("import pybtc;"
|
||||||
|
"f = open('./test/raw_block.txt');"
|
||||||
|
"fc = f.readline();"
|
||||||
|
"pybtc.Block(fc[:-1], format='decoded')")
|
||||||
# print(">>>",block.bits)
|
# print(">>>",block.bits)
|
||||||
# print(">>>",block.hash)
|
# print(">>>",block.hash)
|
||||||
# print(">>>",block.timestamp)
|
# print(">>>",block.timestamp)
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import os, sys
|
|||||||
parentPath = os.path.abspath("..")
|
parentPath = os.path.abspath("..")
|
||||||
if parentPath not in sys.path:
|
if parentPath not in sys.path:
|
||||||
sys.path.insert(0, parentPath)
|
sys.path.insert(0, parentPath)
|
||||||
from pybtc import tools
|
from pybtc.functions import hash as tools
|
||||||
from binascii import unhexlify, hexlify
|
from binascii import unhexlify, hexlify
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ if parentPath not in sys.path:
|
|||||||
|
|
||||||
from secp256k1 import ffi
|
from secp256k1 import ffi
|
||||||
import secp256k1
|
import secp256k1
|
||||||
from pybtc.tools import *
|
from pybtc.functions import *
|
||||||
from pybtc.opcodes import *
|
from pybtc.opcodes import *
|
||||||
from pybtc.transaction import *
|
from pybtc.transaction import *
|
||||||
from pybtc.address import *
|
from pybtc.address import *
|
||||||
|
|||||||
@ -6,8 +6,7 @@ parentPath = os.path.abspath("..")
|
|||||||
if parentPath not in sys.path:
|
if parentPath not in sys.path:
|
||||||
sys.path.insert(0, parentPath)
|
sys.path.insert(0, parentPath)
|
||||||
|
|
||||||
from pybtc.tools import *
|
from pybtc.functions import *
|
||||||
from pybtc.hash import *
|
|
||||||
from pybtc.transaction import *
|
from pybtc.transaction import *
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
from pybtc import address_to_hash as address2hash160
|
from pybtc import address_to_hash as address2hash160
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import random
|
import random
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
|
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
|
|
||||||
|
|
||||||
|
parentPath = os.path.abspath("..")
|
||||||
|
if parentPath not in sys.path:
|
||||||
|
sys.path.insert(0, parentPath)
|
||||||
|
|
||||||
from pybtc.hdwallet import *
|
from pybtc.hdwallet import *
|
||||||
from pybtc.tools import encode_base58, decode_base58
|
from pybtc.tools import encode_base58, decode_base58
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user