Browse Source

support sending to segwit native addresses (bip173)

seed_v14
ThomasV 8 years ago
parent
commit
f56a8702c2
  1. 37
      lib/bitcoin.py
  2. 9
      lib/transaction.py

37
lib/bitcoin.py

@ -29,47 +29,49 @@ import re
import hmac import hmac
import os import os
import ecdsa
import pyaes
from .util import bfh, bh2u, to_string from .util import bfh, bh2u, to_string
from . import version from . import version
from .util import print_error, InvalidPassword, assert_bytes, to_bytes from .util import print_error, InvalidPassword, assert_bytes, to_bytes
from . import segwit_addr
import ecdsa
import pyaes
# Bitcoin network constants # Bitcoin network constants
TESTNET = False TESTNET = False
NOLNET = False NOLNET = False
ADDRTYPE_P2PKH = 0 ADDRTYPE_P2PKH = 0
ADDRTYPE_P2SH = 5 ADDRTYPE_P2SH = 5
ADDRTYPE_P2WPKH = 6 SEGWIT_HRP = "bc"
XPRV_HEADER = 0x0488ade4 XPRV_HEADER = 0x0488ade4
XPUB_HEADER = 0x0488b21e XPUB_HEADER = 0x0488b21e
HEADERS_URL = "https://headers.electrum.org/blockchain_headers" HEADERS_URL = "https://headers.electrum.org/blockchain_headers"
GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
def set_testnet(): def set_testnet():
global ADDRTYPE_P2PKH, ADDRTYPE_P2SH, ADDRTYPE_P2WPKH global ADDRTYPE_P2PKH, ADDRTYPE_P2SH
global XPRV_HEADER, XPUB_HEADER global XPRV_HEADER, XPUB_HEADER
global TESTNET, HEADERS_URL global TESTNET, HEADERS_URL
global GENESIS global GENESIS
global SEGWIT_HRP
TESTNET = True TESTNET = True
ADDRTYPE_P2PKH = 111 ADDRTYPE_P2PKH = 111
ADDRTYPE_P2SH = 196 ADDRTYPE_P2SH = 196
ADDRTYPE_P2WPKH = 3 SEGWIT_HRP = "tb"
XPRV_HEADER = 0x04358394 XPRV_HEADER = 0x04358394
XPUB_HEADER = 0x043587cf XPUB_HEADER = 0x043587cf
HEADERS_URL = "https://headers.electrum.org/testnet_headers" HEADERS_URL = "https://headers.electrum.org/testnet_headers"
GENESIS = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" GENESIS = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
def set_nolnet(): def set_nolnet():
global ADDRTYPE_P2PKH, ADDRTYPE_P2SH, ADDRTYPE_P2WPKH global ADDRTYPE_P2PKH, ADDRTYPE_P2SH
global XPRV_HEADER, XPUB_HEADER global XPRV_HEADER, XPUB_HEADER
global NOLNET, HEADERS_URL global NOLNET, HEADERS_URL
global GENESIS global GENESIS
TESTNET = True TESTNET = True
ADDRTYPE_P2PKH = 0 ADDRTYPE_P2PKH = 0
ADDRTYPE_P2SH = 5 ADDRTYPE_P2SH = 5
ADDRTYPE_P2WPKH = 6
XPRV_HEADER = 0x0488ade4 XPRV_HEADER = 0x0488ade4
XPUB_HEADER = 0x0488b21e XPUB_HEADER = 0x0488b21e
HEADERS_URL = "https://headers.electrum.org/nolnet_headers" HEADERS_URL = "https://headers.electrum.org/nolnet_headers"
@ -290,8 +292,6 @@ def hash_160(public_key):
def hash160_to_b58_address(h160, addrtype, witness_program_version=1): def hash160_to_b58_address(h160, addrtype, witness_program_version=1):
s = bytes([addrtype]) s = bytes([addrtype])
if addrtype == ADDRTYPE_P2WPKH:
s += bytes([witness_program_version]) + b'\x00'
s += h160 s += h160
return base_encode(s+Hash(s)[0:4], base=58) return base_encode(s+Hash(s)[0:4], base=58)
@ -313,11 +313,14 @@ def hash160_to_p2sh(h160):
def public_key_to_p2pkh(public_key): def public_key_to_p2pkh(public_key):
return hash160_to_p2pkh(hash_160(public_key)) return hash160_to_p2pkh(hash_160(public_key))
def hash160_to_segwit_addr(h160):
def public_key_to_p2wpkh(public_key): return segwit_addr.encode(SEGWIT_HRP, 0, h160)
return hash160_to_b58_address(hash_160(public_key), ADDRTYPE_P2WPKH)
def address_to_script(addr): def address_to_script(addr):
if is_segwit_address(addr):
witver, witprog = segwit_addr.decode(SEGWIT_HRP, addr)
script = bytes([witver]).hex() + push_script(bytes(witprog).hex())
return script
addrtype, hash_160 = b58_address_to_hash160(addr) addrtype, hash_160 = b58_address_to_hash160(addr)
if addrtype == ADDRTYPE_P2PKH: if addrtype == ADDRTYPE_P2PKH:
script = '76a9' # op_dup, op_hash_160 script = '76a9' # op_dup, op_hash_160
@ -476,7 +479,11 @@ def address_from_private_key(sec):
address = public_key_to_p2pkh(bfh(public_key)) address = public_key_to_p2pkh(bfh(public_key))
return address return address
def is_address(addr): def is_segwit_address(addr):
witver, witprog = segwit_addr.decode(SEGWIT_HRP, addr)
return witprog is not None
def is_b58_address(addr):
try: try:
addrtype, h = b58_address_to_hash160(addr) addrtype, h = b58_address_to_hash160(addr)
except Exception as e: except Exception as e:
@ -485,6 +492,10 @@ def is_address(addr):
return False return False
return addr == hash160_to_b58_address(h, addrtype) return addr == hash160_to_b58_address(h, addrtype)
def is_address(addr):
return is_segwit_address(addr) or is_b58_address(addr)
def is_p2pkh(addr): def is_p2pkh(addr):
if is_address(addr): if is_address(addr):
addrtype, h = b58_address_to_hash160(addr) addrtype, h = b58_address_to_hash160(addr)

9
lib/transaction.py

@ -393,6 +393,11 @@ def get_address_from_output_script(_bytes):
if match_decoded(decoded, match): if match_decoded(decoded, match):
return TYPE_ADDRESS, hash160_to_p2sh(decoded[1][1]) return TYPE_ADDRESS, hash160_to_p2sh(decoded[1][1])
# segwit address
match = [ opcodes.OP_0, opcodes.OP_PUSHDATA4 ]
if match_decoded(decoded, match):
return TYPE_ADDRESS, hash160_to_segwit_addr(decoded[1][1])
return TYPE_SCRIPT, bh2u(_bytes) return TYPE_SCRIPT, bh2u(_bytes)
@ -584,7 +589,7 @@ class Transaction:
@classmethod @classmethod
def pay_script(self, output_type, addr): def pay_script(self, output_type, addr):
if output_type == TYPE_SCRIPT: if output_type == TYPE_SCRIPT:
return bh2u(addr) return addr
elif output_type == TYPE_ADDRESS: elif output_type == TYPE_ADDRESS:
return bitcoin.address_to_script(addr) return bitcoin.address_to_script(addr)
else: else:
@ -835,7 +840,7 @@ class Transaction:
elif type == TYPE_PUBKEY: elif type == TYPE_PUBKEY:
addr = bitcoin.public_key_to_p2pkh(bfh(x)) addr = bitcoin.public_key_to_p2pkh(bfh(x))
else: else:
addr = 'SCRIPT ' + bh2u(x) addr = 'SCRIPT ' + x
o.append((addr,v)) # consider using yield (addr, v) o.append((addr,v)) # consider using yield (addr, v)
return o return o

Loading…
Cancel
Save