Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implementing address_byte_prefix for addresses/transactions #27

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 18 additions & 19 deletions pybtc/classes/address.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
from pybtc.constants import *
from pybtc.opcodes import *
from pybtc.constants import (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
TESTNET_PRIVATE_KEY_COMPRESSED_PREFIX)
from pybtc.opcodes import OP_CHECKSIG, OP_CHECKMULTISIG
from pybtc.functions.tools import bytes_from_hex, int_to_var_int
from pybtc.functions.script import op_push_data, decode_script
from pybtc.functions.hash import hash160, sha256
from pybtc.functions.address import hash_to_address, public_key_to_p2sh_p2wpkh_script
from pybtc.functions.address import hash_to_address, public_key_to_p2sh_p2wpkh_script
from pybtc.functions.key import (create_private_key,
private_key_to_wif,
is_wif_valid,
wif_to_private_key,
is_public_key_valid,
private_to_public_key)

class PrivateKey():

class PrivateKey:
"""
The class for creating private key object.

Expand All @@ -20,7 +23,6 @@ class PrivateKey():
:param compressed: (optional) if set to True private key corresponding compressed public key,
by default set to True. Recommended use only compressed public key.
:param testnet: (optional) if set to True mean that this private key for testnet Bitcoin network.

"""
def __init__(self, key=None, compressed=True, testnet=False):

Expand Down Expand Up @@ -71,28 +73,27 @@ def __str__(self):
return self.wif


class PublicKey():
class PublicKey:
"""
The class for public key object.

:param key: one of this types allowed:

- private key is instance of ``PrivateKey`` class
- private key HEX encoded string
- private key 32 bytes string
- private key in WIF format
- public key in HEX encoded string
- public key [33/65] bytes string
In case no key specified with HEX or bytes string you have to provide flag for testnet

In case no key specified with HEX or bytes string you have to provide flag for testnet
and compressed key. WIF format and ``PrivateKey`` instance already contain this flags.
For HEX or bytes public key only testnet flag has the meaning, comressed flag is determined
For HEX or bytes public key only testnet flag has the meaning, comressed flag is determined
according to the length of key.

:param compressed: (optional) if set to True private key corresponding compressed public key,
by default set to True. Recommended use only compressed public key.
:param testnet: (optional) if set to True mean that this private key for testnet Bitcoin network.

"""
def __init__(self, key, compressed=True, testnet=False):
if isinstance(key, str):
Expand Down Expand Up @@ -129,17 +130,17 @@ def __str__(self):
return self.hex


class Address():
class Address:
"""
The class for Address object.

:param key: (optional) one of this types allowed:

- private key WIF format
- instance of ``PrivateKey``
- private key HEX encoded string
- instance of ``PublicKey``

In case no key specified new Address will be created with random keys.
:param address_type: (optional) P2PKH, PUBKEY, P2WPKH, P2SH_P2WPKH, by default P2WPKH.
:param compressed: (optional) if set to True private key corresponding compressed public key,
Expand Down Expand Up @@ -237,15 +238,13 @@ def multisig(cls, n, m, public_key_list,

:param n: count of required signatures (max 15).
:param m: count of total addresses of participants (max 15).
:param list address_list: addresses list, allowed types:
:param list address_list: addresses list, allowed types: - TODO

- bytes or HEX encoded private key
- private key in WIF format
- PrivateKey instance,
- bytes or HEX encoded public key
- PublicKey instance


"""
if n > 15 or m > 15 or n > m or n < 1 or m < 1:
raise TypeError("invalid n of m maximum 15 of 15 multisig allowed")
Expand Down
40 changes: 21 additions & 19 deletions pybtc/classes/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
from struct import unpack, pack
from math import ceil
from io import BytesIO
from pybtc.constants import *
from pybtc.opcodes import *
from pybtc.constants import (MAX_AMOUNT,
SIGHASH_ALL,
SIGHASH_SINGLE,
SIGHASH_ANYONECANPAY,
SIGHASH_NONE,
MAINNET_ADDRESS_BYTE_PREFIX)
from pybtc.opcodes import OP_0, BYTE_OPCODE, OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG
from pybtc.functions.tools import (int_to_var_int,
read_var_int,
var_int_to_int,
Expand All @@ -15,8 +20,8 @@
from pybtc.functions.script import get_multisig_public_keys, read_opcode, is_valid_signature_encoding
from pybtc.functions.script import public_key_recovery, delete_from_script
from pybtc.functions.hash import hash160, sha256, double_sha256
from pybtc.functions.address import hash_to_address, address_net_type, address_to_script
from pybtc.classes.address import PrivateKey, Address, ScriptAddress, PublicKey
from pybtc.functions.address import hash_to_address, address_net_type, address_to_script
from pybtc.classes.address import PrivateKey, Address, ScriptAddress, PublicKey
from collections import deque


Expand All @@ -28,18 +33,20 @@ class Transaction(dict):
well be created new empty transaction template.
:param tx_format: "raw" or "decoded" format. Raw format is mean that all transaction represented in bytes
for best performance.
Decoded transaction is represented in human readable format using base68, hex, bech32,
Decoded transaction is represented in human readable format using base68, hex, bech32,
asm and opcodes. By default "decoded" format using.
:param int version: transaction version for new template, by default 1.
:param int lock_time: transaction lock time for new template, by default 0.
:param boolean testnet: address type for "decoded" transaction representation.

"""
def __init__(self, raw_tx=None, format="decoded", version=1,
lock_time=0, testnet=False, auto_commit=True, keep_raw_tx=False):
lock_time=0, testnet=False, auto_commit=True,
keep_raw_tx=False, address_byte_prefix=MAINNET_ADDRESS_BYTE_PREFIX):
if format not in ("decoded", "raw"):
raise ValueError("format error, raw or decoded allowed")
self.auto_commit = auto_commit
self.address_byte_prefix = address_byte_prefix
self["format"] = format
self["testnet"] = testnet
self["segwit"] = False
Expand Down Expand Up @@ -219,7 +226,8 @@ def decode(self, testnet=None):
self["vIn"][i]["address"] = hash_to_address(self["vIn"][i]["addressHash"],
self["testnet"],
sh,
witness_version)
witness_version,
self.address_byte_prefix)
except:
pass
if "scriptPubKey" in self["vIn"][i]:
Expand Down Expand Up @@ -249,7 +257,8 @@ def decode(self, testnet=None):
self["vOut"][i]["address"] = hash_to_address(self["vOut"][i]["addressHash"],
self["testnet"],
sh,
witness_version)
witness_version,
self.address_byte_prefix)
except:
pass
self["vOut"][i]["scriptPubKeyOpcodes"] = decode_script(self["vOut"][i]["scriptPubKey"])
Expand All @@ -261,7 +270,7 @@ def decode(self, testnet=None):

def encode(self):
"""
change Transaction object representation to "raw" bytes format,
change Transaction object representation to "raw" bytes format,
all human readable part will be stripped.

"""
Expand Down Expand Up @@ -348,9 +357,9 @@ def get_stream(stream):

def serialize(self, segwit=True, hex=True):
"""
Get serialized transaction
:param bool segwit: (optional) flag for segwit representation of serialized transaction, by
Get serialized transaction

:param bool segwit: (optional) flag for segwit representation of serialized transaction, by
default True.
:param bool hex: (optional) if set to True return HEX encoded string, by default True.
:return str,bytes: serialized transaction in HEX or bytes.
Expand Down Expand Up @@ -1144,10 +1153,3 @@ def commit(self):
self["fee"] = input_sum - output_sum
else:
self["fee"] = None







34 changes: 24 additions & 10 deletions pybtc/functions/address.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
from pybtc.opcodes import *
from pybtc.constants import *

from pybtc.opcodes import OP_HASH160, OP_EQUAL, OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG, OP_0
from pybtc.constants import (MAINNET_ADDRESS_PREFIX,
TESTNET_ADDRESS_PREFIX,
TESTNET_ADDRESS_PREFIX_2,
TESTNET_ADDRESS_BYTE_PREFIX,
MAINNET_ADDRESS_BYTE_PREFIX,
MAINNET_SCRIPT_ADDRESS_BYTE_PREFIX,
TESTNET_SCRIPT_ADDRESS_BYTE_PREFIX,
TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX,
TESTNET_SEGWIT_ADDRESS_PREFIX,
MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX,
MAINNET_SEGWIT_ADDRESS_PREFIX,
ADDRESS_PREFIX_LIST,
TESTNET_SCRIPT_ADDRESS_PREFIX,
MAINNET_SCRIPT_ADDRESS_PREFIX,
SCRIPT_TYPES)
from pybtc.functions.tools import bytes_from_hex, get_bytes
from pybtc.functions.hash import double_sha256, hash160
from pybtc.functions.encode import (encode_base58,
Expand Down Expand Up @@ -42,7 +55,8 @@ def public_key_to_address(pubkey, testnet=False, p2sh_p2wpkh=False, witness_vers
witness_version=witness_version)


def hash_to_address(address_hash, testnet=False, script_hash=False, witness_version=0):
def hash_to_address(address_hash, testnet=False, script_hash=False,
witness_version=0, address_byte_prefix=MAINNET_ADDRESS_BYTE_PREFIX):
"""
Get address from public key/script hash. In case PUBKEY, P2PKH, P2PKH public key/script hash is SHA256+RIPEMD160,
P2WSH script hash is SHA256.
Expand All @@ -64,7 +78,7 @@ def hash_to_address(address_hash, testnet=False, script_hash=False, witness_vers
if testnet:
prefix = TESTNET_ADDRESS_BYTE_PREFIX
else:
prefix = MAINNET_ADDRESS_BYTE_PREFIX
prefix = address_byte_prefix
address_hash = b"%s%s" % (prefix, address_hash)
address_hash += double_sha256(address_hash)[:4]
return encode_base58(address_hash)
Expand All @@ -85,7 +99,7 @@ def hash_to_address(address_hash, testnet=False, script_hash=False, witness_vers
prefix = TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX
hrp = TESTNET_SEGWIT_ADDRESS_PREFIX
else:
prefix = MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX
prefix = address_byte_prefix
hrp = MAINNET_SEGWIT_ADDRESS_PREFIX

address_hash = b"%s%s" % (witness_version.to_bytes(1, "big"),
Expand Down Expand Up @@ -116,11 +130,11 @@ def address_to_hash(address, hex=True):

def address_type(address, num=False):
"""
Get address type.
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.
:return: address type in string or numeric format.
"""
if address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX,
MAINNET_SCRIPT_ADDRESS_PREFIX):
Expand All @@ -144,10 +158,10 @@ def address_type(address, num=False):

def address_net_type(address):
"""
Get address network type.
Get address network type.

:param address: address in base58 or bech32 format.
:return: address network type in string format or None.
:return: address network type in string format or None.
"""
if address[0] in (MAINNET_SCRIPT_ADDRESS_PREFIX,
MAINNET_ADDRESS_PREFIX):
Expand Down