Skip to content
This repository has been archived by the owner on Aug 5, 2023. It is now read-only.

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
davidlj95 committed Jul 6, 2018
1 parent f4989b1 commit 25ef87f
Show file tree
Hide file tree
Showing 19 changed files with 757 additions and 18 deletions.
7 changes: 5 additions & 2 deletions bitcoin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
Intended to create transactions with smart contracts in Bitcoin in an easy
way
"""
from .address import P2PKHAddress, AddressPKHLengthError
from .address import AddressPKHLengthError, AddressSHLengthError, \
P2PKHAddress, P2SHAddress
from .encoding import b58decode, b58encode, bech32decode, bech32encode

__all__ = ["P2PKHAddress", "AddressPKHLengthError"]
__all__ = ["AddressPKHLengthError", "AddressSHLengthError", "P2PKHAddress",
"P2SHAddress", "b58decode", "b58encode"]
4 changes: 3 additions & 1 deletion bitcoin/address/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
Contains models to handle Bitcoin addresses
"""
from .p2pkh import P2PKHAddress, AddressPKHLengthError
from .p2sh import P2SHAddress, AddressSHLengthError

__all__ = ["P2PKHAddress", "AddressPKHLengthError"]
__all__ = ["P2PKHAddress", "P2SHAddress", "AddressPKHLengthError",
"AddressSHLengthError"]
44 changes: 29 additions & 15 deletions bitcoin/address/p2pkh.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
"""Models P2PKH Addresses.
"""Models P2PKH_ Addresses.
A P2PKH address is used by user to send bitcoins to another user who controls
.. _P2PKH: https://en.bitcoin.it/wiki/Transaction#Pay-to-PubkeyHash
A P2PKH_ address is used by user to send bitcoins to another user who controls
the private key behind the public key (whose hash appears in the address)
Most information was extracted from the `Bitcoin Wiki`__.
__ P2PKH_
"""

# Constants
Expand Down Expand Up @@ -29,38 +35,42 @@ class P2PKHAddress:
def __init__(self, public_key_hash: bytes) -> None:
"""Initializes a P2PKH given its public key hash.
Modifies the attribute :py:attr:`_script_hash`
Args:
public_key_hash: public key hash to set
Raises:
AssertionError: public_key_hash argument is not a bytes object
AddressPKHLengthError: public_key_hash argument hsa not the
AddressPKHLengthError: public_key_hash argument has not the
proper length of a public key hash
"""
self._public_key_hash = None
self.public_key_hash = public_key_hash

def do_things(self, obj: str) -> bytes:
"""Does some things.
Args:
obj: object of options
Returns:
things modified by :py:obj:`obj` as bytes
"""
return bytes()

@property
def public_key_hash(self) -> bytes:
"""Returns the public key hash stored in the address.
Returns:
public key hash bytes
:getter: Returns the public key hash as bytes object
:setter: Sets the public key hash, while verifying the length and
type
"""
return self._public_key_hash

@public_key_hash.setter
def public_key_hash(self, public_key_hash: bytes) -> None:
"""Sets the public key hash of the address.
Args:
public_key_hash: public key hash to set
Raises:
AssertionError: public_key_hash argument is not a bytes object
AddressPKHLengthError: public_key_hash argument hsa not the
proper length of a public key hash
"""
assert isinstance(public_key_hash, bytes), \
"Public key hash must be exactly %d bytes" % PKH_LENGTH

Expand All @@ -77,6 +87,10 @@ def from_hex(public_key_hash_hex: str) -> P2PKHAddress:
Converts the hexadecimal string into bytes and then uses those bytes to
create a P2PKH address.
>>> 1+1
2
Args:
public_key_hash_hex: string containing public key hash in hexadecimal
Expand Down
99 changes: 99 additions & 0 deletions bitcoin/address/p2sh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"""Models P2SH_ Addresses.
.. _P2SH: https://en.bitcoin.it/wiki/Transaction#Pay-to-Script-Hash
A P2SH_ address is used by user to send bitcoins to a Bitcoin smart
contract
Most information was extracted from the `Bitcoin Wiki`__.
__ P2SH_
"""

# Constants
SH_LENGTH = 20
"""
int: length of the script hashes stored in addresses
"""


# Errors
class AddressSHLengthError(ValueError):
"""Error raised when the redeem script hash has an incorrect length"""
pass


# Classes
class P2SHAddress:
"""Models a legacy P2SH Address
Attributes:
_script_hash (bytes): public key hash of the address
"""
__slots__ = ["_script_hash"]

def __init__(self, script_hash: bytes) -> None:
"""Initializes a P2SH given its script hash.
Modifies the attribute :py:attr:`_script_hash`
Args:
script_hash: script hash to set
Raises:
AssertionError: script_hash argument is not a bytes object
AddressSHLengthError: script_hash argument has not the
proper length of a script hash
"""
self._script_hash = None
self.script_hash = script_hash

def do_things(self, obj: str) -> bytes:
"""Does some things.
Args:
obj: object of options
Returns:
things modified by :py:obj:`obj` as bytes
"""
return bytes()

@property
def script_hash(self) -> bytes:
"""Returns the public key hash stored in the address.
:getter: Returns the script hash as bytes object
:setter: Sets the script hash, while verifying the length and
type
"""
return self._script_hash

@script_hash.setter
def script_hash(self, public_key_hash: bytes) -> None:
assert isinstance(public_key_hash, bytes), \
"Script hash must be exactly %d bytes" % SH_LENGTH

if len(public_key_hash) != SH_LENGTH:
raise AddressSHLengthError

self._script_hash = public_key_hash


# Methods
def from_hex(script_hash_hex: str) -> P2SHAddress:
"""Creates a P2SH address from script hash in hexadecimal.
Converts the hexadecimal string into bytes and then uses those bytes to
create a P2SH address.
>>> 2+3
5
Args:
script_hash_hex: string containing script hash in hexadecimal
Returns:
pay to script hash address
"""
return P2SHAddress(bytes.fromhex(script_hash_hex))
5 changes: 5 additions & 0 deletions bitcoin/encoding/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Provides methods to allow encoding and decoding Bitcoin addresses."""
from .base58 import encode as b58encode, decode as b58decode
from .bech32 import encode as bech32encode, decode as bech32decode

__all__ = ["b58encode", "b58decode", "bech32encode", "bech32decode"]
68 changes: 68 additions & 0 deletions bitcoin/encoding/base58.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""Provides methods to encode/decode to/from base58."""

# Libraries
import math

# Constants
ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
"""
str: base58 domain
"""


def encode(value: bytes) -> str:
"""Encodes bytes using base58 convention into an human-readable string.
**Sources**
- `Bitcoin Wiki: base 58 \
<https://en.bitcoin.it/wiki/Base58Check_encoding>`_
"""
assert isinstance(value, bytes), "Expected bytes, given: " + type(value)
output = ""
# Convert bytes to integer
number = int.from_bytes(value, byteorder='big')

while number > 0:
number, residuum = divmod(number, 58)
output += ALPHABET[residuum]

# Convert leading zeros
leading_zeros = 0

for element in value:
if element == 0:
leading_zeros += 1
else:
break

output += ALPHABET[0] * leading_zeros

return output[::-1]


def decode(value: str) -> bytes:
"""Decodes a base58 string into a bytes object."""
assert isinstance(value, str), "Expected a string object, given: " + \
type(value)
number = 0

for char in value:
number *= 58
if char not in ALPHABET:
raise ValueError("Character not valid to decode from Base58")
number += ALPHABET.index(char)

# Convert integer to bytes
number_bytes = number.to_bytes(math.ceil(number.bit_length()/8), "big")

# Check leading zeros to put them back again
leading_zeros = 0

for char in value:
if char == ALPHABET[0]:
leading_zeros += 1
else:
break
number_bytes = b'\x00'*leading_zeros + number_bytes

return number_bytes

0 comments on commit 25ef87f

Please sign in to comment.