diff --git a/README.md b/README.md index 9038829..8cfa5cb 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,79 @@ # pybtc Python bitcoin library + + +### Basic Examples + +#### Create private key + + >>> from pybtc import * + >>> create_priv() + b'\xc8\xf5tGf\x00+4\x1c\xe3\xb6\x00\xf4\x14w\x1d\xf0{jiY&4`v\xd4\tmv!\x0f\x1f' + >>> priv = create_priv() + >>> priv + b'_`\xd7@\x9e\xdb\xbbB5O%@\xd6\x92\xb1\x0e*\xcd\xb6\x89!\xa3JE\xb0\xb6:\x8c\x04\x88\xc9\xa5' + >>> priv2WIF(priv) + 'KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW' + >>> priv2WIF(priv, compressed = False) # Mainnet compressed WIF format + '5JYHtgBjYbLT3ZkhGHHCivscdMdDKeVTZBgq5ZK51fyKpqKDhYv' # Mainnet uncompressed WIF format + >>> priv2WIF(priv, testnet = True) + 'cQn71zxEDWF77m386rfe7PHTshLF3kaJH6KGKY5GD5fcLsCqpPbg' + >>> priv2WIF(priv, compressed = True, testnet = True) # Testnet compressed WIF format + 'cQn71zxEDWF77m386rfe7PHTshLF3kaJH6KGKY5GD5fcLsCqpPbg' + >>> priv2WIF(priv, compressed = False, testnet = True) # Testnet uncompressed WIF format + '92JvUR1H8pQb1dFytdB7bXRaH1yvUp2eu8YnABfaMQiNbuKiPVL' + >>> + >>> WIF2priv("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW") + b'_`\xd7@\x9e\xdb\xbbB5O%@\xd6\x92\xb1\x0e*\xcd\xb6\x89!\xa3JE\xb0\xb6:\x8c\x04\x88\xc9\xa5' + +#### Public key from private key + + >>> from pybtc import * + >>> priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW") + b'\x02\xb1-\xc2\x03u\xda\x00*7t\xb9c\xe4A\xdb\x1c\xe0\x89\xb8W\x13\x86\xbe\x82\xee(\x11nrj\xb06' + >>> priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW", hex = True) + '02b12dc20375da002a3774b963e441db1ce089b8571386be82ee28116e726ab036' + >>> + >>> priv = WIF2priv("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW") + >>> priv + b'_`\xd7@\x9e\xdb\xbbB5O%@\xd6\x92\xb1\x0e*\xcd\xb6\x89!\xa3JE\xb0\xb6:\x8c\x04\x88\xc9\xa5' + >>> + >>> priv2pub(priv, hex = True) + '02b12dc20375da002a3774b963e441db1ce089b8571386be82ee28116e726ab036' + >>> + +#### Address from public key/private key + + >>> from pybtc import * + >>> # address in bech32 format + ... + >>> pub2address(priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW")) + 'bc1q3hs6985qftzrvfl7aqcshsf7equapuuxzr2kcv' + >>> + >>> # address in legacy format + ... + >>> pub2address(priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW"), witness_version = None) + '1DwCaTcMTT5kZmH4wCevDe5nyzffi2Bz9p' + >>> + >>> # uncompressed public key deprecated for bech32 segwit addresses fromat + ... + >>> pub2address(priv2pub("5JYHtgBjYbLT3ZkhGHHCivscdMdDKeVTZBgq5ZK51fyKpqKDhYv")) + Traceback (most recent call last): + File "", line 1, in + File "/usr/local/lib/python3.6/site-packages/pybtc/tools.py", line 233, in pub2address + assert len(pubkey) == 33 + AssertionError + >>> + >>> # uncompressed public key legacy format + ... + >>> pub2address(priv2pub("5JYHtgBjYbLT3ZkhGHHCivscdMdDKeVTZBgq5ZK51fyKpqKDhYv"), witness_version = None) + '1EbTeoa1QgZaSHZFznrhNdKrRbbQupVwuZ' + >>> + >>> # testnet addresses + ... + >>> pub2address(priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW"), testnet = True) + 'tb1q3hs6985qftzrvfl7aqcshsf7equapuuxg939rl' + >>> pub2address(priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW"), witness_version = None, testnet = True) + 'mtT9sWhLGUX1LskgemdJ3ZJ7qzGNaygcXP' + >>> + diff --git a/pybtc/tools.py b/pybtc/tools.py index 4e94eec..2f89ed3 100644 --- a/pybtc/tools.py +++ b/pybtc/tools.py @@ -34,7 +34,7 @@ def priv_from_int(k): return int.to_bytes(k,byteorder="big",length=32) -def priv2WIF(h, compressed = False, testnet = False): +def priv2WIF(h, compressed = True, testnet = False): #uncompressed: 0x80 + [32-byte secret] + [4 bytes of Hash() of previous 33 bytes], base58 encoded #compressed: 0x80 + [32-byte secret] + 0x01 + [4 bytes of Hash() previous 34 bytes], base58 encoded if type(h) == str: @@ -213,13 +213,19 @@ def address2script(address): return OPCODE["OP_0"] + bytes([len(h)]) + h raise Exception("Unknown address") +def script_P2SH_P2WPKH(pubkey, hash = False): + assert len(pubkey) == 33 + if hash: + return hash160(b'\x00\x14' + hash160(pubkey)) + return b'\x00\x14' + hash160(pubkey) + def pub2address(pubkey, testnet = False, - inside_p2sh = False, + p2sh_p2wpkh = False, witness_version = 0): if type(pubkey) == str: pubkey = unhexlify(pubkey) - if inside_p2sh: + if p2sh_p2wpkh: assert len(pubkey) == 33 h = hash160(b'\x00\x14' + hash160(pubkey)) else: @@ -227,7 +233,7 @@ def pub2address(pubkey, testnet = False, assert len(pubkey) == 33 h = hash160(pubkey) return hash2address(h, testnet = testnet, - script_hash = inside_p2sh, + script_hash = p2sh_p2wpkh, witness_version = witness_version) # def pub2P2SH_P2WPKH_hash(pubkey): diff --git a/test.py b/tests/test.py similarity index 99% rename from test.py rename to tests/test.py index fec37ce..afb121b 100644 --- a/test.py +++ b/tests/test.py @@ -1,4 +1,5 @@ import unittest + import test testLoad = unittest.TestLoader() diff --git a/test/__init__.py b/tests/test/__init__.py similarity index 100% rename from test/__init__.py rename to tests/test/__init__.py diff --git a/test/address_functions.py b/tests/test/address_functions.py similarity index 99% rename from test/address_functions.py rename to tests/test/address_functions.py index f97ed07..5094b8d 100644 --- a/test/address_functions.py +++ b/tests/test/address_functions.py @@ -106,7 +106,7 @@ class AddressFunctionsTests(unittest.TestCase): self.assertEqual(tools.pub2address(pc, witness_version=None, testnet=1), "mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c") p = "L32a8Mo1LgvjrVDbzcc3NkuUfkpoLsf2Y2oEWkV4t1KpQdFzuyff" pk = tools.priv2pub(p) - self.assertEqual(tools.pub2address(pk, inside_p2sh=1,witness_version=None), "33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw") + self.assertEqual(tools.pub2address(pk, p2sh_p2wpkh=1,witness_version=None), "33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw") def test_is_address_valid(self): self.assertEqual(tools.is_address_valid("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), 1) diff --git a/test/block.py b/tests/test/block.py similarity index 99% rename from test/block.py rename to tests/test/block.py index 2d4f24c..f78b4d2 100644 --- a/test/block.py +++ b/tests/test/block.py @@ -592,11 +592,11 @@ class BlockDeserializeTests(unittest.TestCase): block = blockchain.Block.deserialize(block_e) - print(">>>",block.bits) - print(">>>",block.hash) - print(">>>",block.timestamp) - target = int.from_bytes(block.bits[1:], 'big') * (2 ** (8 * (block.bits[0] - 3))) - print(int.from_bytes(block.hash, 'big')>>",block.bits) + # print(">>>",block.hash) + # print(">>>",block.timestamp) + # target = int.from_bytes(block.bits[1:], 'big') * (2 ** (8 * (block.bits[0] - 3))) + # print(int.from_bytes(block.hash, 'big') OP_EQUALVERIFY OP_CHECKSIG") self.assertEqual(s.op_sig_count, 1) @@ -24,7 +24,7 @@ class ScriptDeserializeTests(unittest.TestCase): self.assertEqual(s.type, "P2SH") self.assertEqual(s.ntype, 1) self.assertEqual(s.asm, "OP_HASH160 69f37572ab1b69f304f987b119e2450e0b71bf5c OP_EQUAL") - self.assertEqual(s.address[0], address2hash160("3BMEXVsYyfKB5h3m53XRSFHkqi1zPwsvcK")) + self.assertEqual(s.address[0], address2hash("3BMEXVsYyfKB5h3m53XRSFHkqi1zPwsvcK")) self.assertEqual(s.pattern, "OP_HASH160 <20> OP_EQUAL") self.assertEqual(s.op_sig_count, 0) diff --git a/test/sighash.py b/tests/test/sighash.py similarity index 100% rename from test/sighash.py rename to tests/test/sighash.py diff --git a/test/transaction_deserialize.py b/tests/test/transaction_deserialize.py similarity index 100% rename from test/transaction_deserialize.py rename to tests/test/transaction_deserialize.py