commit f56a8702c2b52ede1fe8b226736439d76eabd3f4
parent 5f35081bc9156297c9d3df6c585475577493d056
Author: ThomasV <thomasv@electrum.org>
Date: Thu, 31 Aug 2017 15:29:15 +0200
support sending to segwit native addresses (bip173)
Diffstat:
2 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/lib/bitcoin.py b/lib/bitcoin.py
@@ -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"
@@ -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)
@@ -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
@@ -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:
@@ -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)
diff --git a/lib/transaction.py b/lib/transaction.py
@@ -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)
@@ -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:
@@ -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