URI: 
       tsupport sending to segwit native addresses (bip173) - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit f56a8702c2b52ede1fe8b226736439d76eabd3f4
   DIR parent 5f35081bc9156297c9d3df6c585475577493d056
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Thu, 31 Aug 2017 15:29:15 +0200
       
       support sending to segwit native addresses (bip173)
       
       Diffstat:
         M lib/bitcoin.py                      |      37 ++++++++++++++++++++-----------
         M lib/transaction.py                  |       9 +++++++--
       
       2 files changed, 31 insertions(+), 15 deletions(-)
       ---
   DIR diff --git a/lib/bitcoin.py b/lib/bitcoin.py
       t@@ -29,47 +29,49 @@ import re
        import hmac
        import os
        
       +import ecdsa
       +import pyaes
       +
        from .util import bfh, bh2u, to_string
        from . import version
        from .util import print_error, InvalidPassword, assert_bytes, to_bytes
       +from . import segwit_addr
        
       -import ecdsa
       -import pyaes
        
        # Bitcoin network constants
        TESTNET = False
        NOLNET = False
        ADDRTYPE_P2PKH = 0
        ADDRTYPE_P2SH = 5
       -ADDRTYPE_P2WPKH = 6
       +SEGWIT_HRP = "bc"
        XPRV_HEADER = 0x0488ade4
        XPUB_HEADER = 0x0488b21e
        HEADERS_URL = "https://headers.electrum.org/blockchain_headers"
        GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
        
        def set_testnet():
       -    global ADDRTYPE_P2PKH, ADDRTYPE_P2SH, ADDRTYPE_P2WPKH
       +    global ADDRTYPE_P2PKH, ADDRTYPE_P2SH
            global XPRV_HEADER, XPUB_HEADER
            global TESTNET, HEADERS_URL
            global GENESIS
       +    global SEGWIT_HRP
            TESTNET = True
            ADDRTYPE_P2PKH = 111
            ADDRTYPE_P2SH = 196
       -    ADDRTYPE_P2WPKH = 3
       +    SEGWIT_HRP = "tb"
            XPRV_HEADER = 0x04358394
            XPUB_HEADER = 0x043587cf
            HEADERS_URL = "https://headers.electrum.org/testnet_headers"
            GENESIS = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
        
        def set_nolnet():
       -    global ADDRTYPE_P2PKH, ADDRTYPE_P2SH, ADDRTYPE_P2WPKH
       +    global ADDRTYPE_P2PKH, ADDRTYPE_P2SH
            global XPRV_HEADER, XPUB_HEADER
            global NOLNET, HEADERS_URL
            global GENESIS
            TESTNET = True
            ADDRTYPE_P2PKH = 0
            ADDRTYPE_P2SH = 5
       -    ADDRTYPE_P2WPKH = 6
            XPRV_HEADER = 0x0488ade4
            XPUB_HEADER = 0x0488b21e
            HEADERS_URL = "https://headers.electrum.org/nolnet_headers"
       t@@ -290,8 +292,6 @@ def hash_160(public_key):
        
        def hash160_to_b58_address(h160, addrtype, witness_program_version=1):
            s = bytes([addrtype])
       -    if addrtype == ADDRTYPE_P2WPKH:
       -        s += bytes([witness_program_version]) + b'\x00'
            s += h160
            return base_encode(s+Hash(s)[0:4], base=58)
        
       t@@ -313,11 +313,14 @@ def hash160_to_p2sh(h160):
        def public_key_to_p2pkh(public_key):
            return hash160_to_p2pkh(hash_160(public_key))
        
       -
       -def public_key_to_p2wpkh(public_key):
       -    return hash160_to_b58_address(hash_160(public_key), ADDRTYPE_P2WPKH)
       +def hash160_to_segwit_addr(h160):
       +    return segwit_addr.encode(SEGWIT_HRP, 0, h160)
        
        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)
            if addrtype == ADDRTYPE_P2PKH:
                script = '76a9'                                      # op_dup, op_hash_160
       t@@ -476,7 +479,11 @@ def address_from_private_key(sec):
            address = public_key_to_p2pkh(bfh(public_key))
            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:
                addrtype, h = b58_address_to_hash160(addr)
            except Exception as e:
       t@@ -485,6 +492,10 @@ def is_address(addr):
                return False
            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):
            if is_address(addr):
                addrtype, h = b58_address_to_hash160(addr)
   DIR diff --git a/lib/transaction.py b/lib/transaction.py
       t@@ -393,6 +393,11 @@ def get_address_from_output_script(_bytes):
            if match_decoded(decoded, match):
                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)
        
        
       t@@ -584,7 +589,7 @@ class Transaction:
            @classmethod
            def pay_script(self, output_type, addr):
                if output_type == TYPE_SCRIPT:
       -            return bh2u(addr)
       +            return addr
                elif output_type == TYPE_ADDRESS:
                    return bitcoin.address_to_script(addr)
                else:
       t@@ -835,7 +840,7 @@ class Transaction:
                    elif type == TYPE_PUBKEY:
                        addr = bitcoin.public_key_to_p2pkh(bfh(x))
                    else:
       -                addr = 'SCRIPT ' + bh2u(x)
       +                addr = 'SCRIPT ' + x
                    o.append((addr,v))      # consider using yield (addr, v)
                return o