remove segwit from lib
This commit is contained in:
parent
a154b9c2b6
commit
fc0d01ec2c
|
@ -240,7 +240,7 @@ class BaseWizard(object):
|
|||
|
||||
def on_hw_derivation(self, name, device_info, derivation):
|
||||
from .keystore import hardware_keystore
|
||||
xtype = 'p2wpkh-p2sh' if derivation.startswith("m/49'/") else 'standard'
|
||||
xtype = 'standard'
|
||||
try:
|
||||
xpub = self.plugin.get_xpub(device_info.device.id_, derivation, xtype, self)
|
||||
except BaseException as e:
|
||||
|
@ -271,7 +271,7 @@ class BaseWizard(object):
|
|||
def restore_from_seed(self):
|
||||
self.opt_bip39 = True
|
||||
self.opt_ext = True
|
||||
is_cosigning_seed = lambda x: bitcoin.seed_type(x) in ['standard', 'segwit']
|
||||
is_cosigning_seed = lambda x: bitcoin.seed_type(x) in ['standard']
|
||||
test = bitcoin.is_seed if self.wallet_type == 'standard' else is_cosigning_seed
|
||||
self.restore_seed_dialog(run_next=self.on_restore_seed, test=test)
|
||||
|
||||
|
@ -280,7 +280,7 @@ class BaseWizard(object):
|
|||
if self.seed_type == 'bip39':
|
||||
f = lambda passphrase: self.on_restore_bip39(seed, passphrase)
|
||||
self.passphrase_dialog(run_next=f) if is_ext else f('')
|
||||
elif self.seed_type in ['standard', 'segwit']:
|
||||
elif self.seed_type in ['standard']:
|
||||
f = lambda passphrase: self.run('create_keystore', seed, passphrase)
|
||||
self.passphrase_dialog(run_next=f) if is_ext else f('')
|
||||
elif self.seed_type == 'old':
|
||||
|
@ -313,7 +313,7 @@ class BaseWizard(object):
|
|||
from .bitcoin import xpub_type
|
||||
t1 = xpub_type(k.xpub)
|
||||
if self.wallet_type == 'standard':
|
||||
if has_xpub and t1 not in ['standard', 'p2wpkh', 'p2wpkh-p2sh']:
|
||||
if has_xpub and t1 not in ['standard']:
|
||||
self.show_error(_('Wrong key type') + ' %s'%t1)
|
||||
self.run('choose_keystore')
|
||||
return
|
||||
|
@ -321,7 +321,7 @@ class BaseWizard(object):
|
|||
self.run('create_wallet')
|
||||
elif self.wallet_type == 'multisig':
|
||||
assert has_xpub
|
||||
if t1 not in ['standard', 'p2wsh', 'p2wsh-p2sh']:
|
||||
if t1 not in ['standard']:
|
||||
self.show_error(_('Wrong key type') + ' %s'%t1)
|
||||
self.run('choose_keystore')
|
||||
return
|
||||
|
@ -380,17 +380,12 @@ class BaseWizard(object):
|
|||
title = _('Choose Seed type')
|
||||
message = ' '.join([
|
||||
"The type of addresses used by your wallet will depend on your seed.",
|
||||
"Segwit wallets use bech32 addresses, defined in BIP173.",
|
||||
"Please note that websites and other wallets may not support these addresses yet.",
|
||||
"Thus, you might want to keep using a non-segwit wallet in order to be able to receive bitcoins during the transition period."
|
||||
])
|
||||
choices = [
|
||||
('create_standard_seed', _('Standard')),
|
||||
('create_segwit_seed', _('Segwit')),
|
||||
]
|
||||
self.choice_dialog(title=title, message=message, choices=choices, run_next=self.run)
|
||||
|
||||
def create_segwit_seed(self): self.create_seed('segwit')
|
||||
def create_standard_seed(self): self.create_seed('standard')
|
||||
|
||||
def create_seed(self, seed_type):
|
||||
|
|
|
@ -35,7 +35,6 @@ import pyaes
|
|||
from .util import bfh, bh2u, to_string
|
||||
from . import version
|
||||
from .util import print_error, InvalidPassword, assert_bytes, to_bytes, inv_dict
|
||||
from . import segwit_addr
|
||||
|
||||
def read_json_dict(filename):
|
||||
path = os.path.join(os.path.dirname(__file__), filename)
|
||||
|
@ -51,21 +50,11 @@ def read_json_dict(filename):
|
|||
|
||||
# Version numbers for BIP32 extended keys
|
||||
# standard: xprv, xpub
|
||||
# segwit in p2sh: yprv, ypub
|
||||
# native segwit: zprv, zpub
|
||||
XPRV_HEADERS = {
|
||||
'standard': 0x0488ade4,
|
||||
'p2wpkh-p2sh': 0x049d7878,
|
||||
'p2wsh-p2sh': 0x295b005,
|
||||
'p2wpkh': 0x4b2430c,
|
||||
'p2wsh': 0x2aa7a99
|
||||
}
|
||||
XPUB_HEADERS = {
|
||||
'standard': 0x0488b21e,
|
||||
'p2wpkh-p2sh': 0x049d7cb2,
|
||||
'p2wsh-p2sh': 0x295b43f,
|
||||
'p2wpkh': 0x4b24746,
|
||||
'p2wsh': 0x2aa7ed3
|
||||
}
|
||||
|
||||
|
||||
|
@ -282,8 +271,6 @@ def seed_type(x):
|
|||
return 'old'
|
||||
elif is_new_seed(x):
|
||||
return 'standard'
|
||||
elif is_new_seed(x, version.SEED_PREFIX_SW):
|
||||
return 'segwit'
|
||||
elif is_new_seed(x, version.SEED_PREFIX_2FA):
|
||||
return '2fa'
|
||||
return ''
|
||||
|
@ -323,7 +310,7 @@ def hash_160(public_key):
|
|||
return md.digest()
|
||||
|
||||
|
||||
def hash160_to_b58_address(h160, addrtype, witness_program_version=1):
|
||||
def hash160_to_b58_address(h160, addrtype):
|
||||
s = bytes([addrtype])
|
||||
s += h160
|
||||
return base_encode(s+Hash(s)[0:4], base=58)
|
||||
|
@ -344,42 +331,15 @@ def hash160_to_p2sh(h160):
|
|||
def public_key_to_p2pkh(public_key):
|
||||
return hash160_to_p2pkh(hash_160(public_key))
|
||||
|
||||
def hash_to_segwit_addr(h):
|
||||
return segwit_addr.encode(NetworkConstants.SEGWIT_HRP, 0, h)
|
||||
|
||||
def public_key_to_p2wpkh(public_key):
|
||||
return hash_to_segwit_addr(hash_160(public_key))
|
||||
|
||||
def script_to_p2wsh(script):
|
||||
return hash_to_segwit_addr(sha256(bfh(script)))
|
||||
|
||||
def p2wpkh_nested_script(pubkey):
|
||||
pkh = bh2u(hash_160(bfh(pubkey)))
|
||||
return '00' + push_script(pkh)
|
||||
|
||||
def p2wsh_nested_script(witness_script):
|
||||
wsh = bh2u(sha256(bfh(witness_script)))
|
||||
return '00' + push_script(wsh)
|
||||
|
||||
def pubkey_to_address(txin_type, pubkey):
|
||||
if txin_type == 'p2pkh':
|
||||
return public_key_to_p2pkh(bfh(pubkey))
|
||||
elif txin_type == 'p2wpkh':
|
||||
return hash_to_segwit_addr(hash_160(bfh(pubkey)))
|
||||
elif txin_type == 'p2wpkh-p2sh':
|
||||
scriptSig = p2wpkh_nested_script(pubkey)
|
||||
return hash160_to_p2sh(hash_160(bfh(scriptSig)))
|
||||
else:
|
||||
raise NotImplementedError(txin_type)
|
||||
|
||||
def redeem_script_to_address(txin_type, redeem_script):
|
||||
if txin_type == 'p2sh':
|
||||
return hash160_to_p2sh(hash_160(bfh(redeem_script)))
|
||||
elif txin_type == 'p2wsh':
|
||||
return script_to_p2wsh(redeem_script)
|
||||
elif txin_type == 'p2wsh-p2sh':
|
||||
scriptSig = p2wsh_nested_script(redeem_script)
|
||||
return hash160_to_p2sh(hash_160(bfh(scriptSig)))
|
||||
else:
|
||||
raise NotImplementedError(txin_type)
|
||||
|
||||
|
@ -391,13 +351,6 @@ def script_to_address(script):
|
|||
return addr
|
||||
|
||||
def address_to_script(addr):
|
||||
witver, witprog = segwit_addr.decode(NetworkConstants.SEGWIT_HRP, addr)
|
||||
if witprog is not None:
|
||||
assert (0 <= witver <= 16)
|
||||
OP_n = witver + 0x50 if witver > 0 else 0
|
||||
script = bh2u(bytes([OP_n]))
|
||||
script += push_script(bh2u(bytes(witprog)))
|
||||
return script
|
||||
addrtype, hash_160 = b58_address_to_hash160(addr)
|
||||
if addrtype == NetworkConstants.ADDRTYPE_P2PKH:
|
||||
script = '76a9' # op_dup, op_hash_160
|
||||
|
@ -508,15 +461,9 @@ def DecodeBase58Check(psz):
|
|||
|
||||
|
||||
|
||||
# extended key export format for segwit
|
||||
|
||||
SCRIPT_TYPES = {
|
||||
'p2pkh':0,
|
||||
'p2wpkh':1,
|
||||
'p2wpkh-p2sh':2,
|
||||
'p2sh':5,
|
||||
'p2wsh':6,
|
||||
'p2wsh-p2sh':7
|
||||
}
|
||||
|
||||
|
||||
|
@ -567,13 +514,6 @@ def address_from_private_key(sec):
|
|||
public_key = public_key_from_private_key(privkey, compressed)
|
||||
return pubkey_to_address(txin_type, public_key)
|
||||
|
||||
def is_segwit_address(addr):
|
||||
try:
|
||||
witver, witprog = segwit_addr.decode(NetworkConstants.SEGWIT_HRP, addr)
|
||||
except Exception as e:
|
||||
return False
|
||||
return witprog is not None
|
||||
|
||||
def is_b58_address(addr):
|
||||
try:
|
||||
addrtype, h = b58_address_to_hash160(addr)
|
||||
|
@ -584,7 +524,7 @@ def is_b58_address(addr):
|
|||
return addr == hash160_to_b58_address(h, addrtype)
|
||||
|
||||
def is_address(addr):
|
||||
return is_segwit_address(addr) or is_b58_address(addr)
|
||||
return is_b58_address(addr)
|
||||
|
||||
|
||||
def is_private_key(key):
|
||||
|
@ -628,7 +568,7 @@ def verify_message(address, sig, message):
|
|||
public_key, compressed = pubkey_from_signature(sig, h)
|
||||
# check public key using the address
|
||||
pubkey = point_to_ser(public_key.pubkey.point, compressed)
|
||||
for txin_type in ['p2pkh','p2wpkh','p2wpkh-p2sh']:
|
||||
for txin_type in ['p2pkh']:
|
||||
addr = pubkey_to_address(txin_type, bh2u(pubkey))
|
||||
if address == addr:
|
||||
break
|
||||
|
|
|
@ -255,14 +255,6 @@ class Blockchain(util.PrintError):
|
|||
def get_hash(self, height):
|
||||
return hash_header(self.read_header(height))
|
||||
|
||||
def BIP9(self, height, flag):
|
||||
v = self.read_header(height)['version']
|
||||
return ((v & 0xE0000000) == 0x20000000) and ((v & flag) == flag)
|
||||
|
||||
def segwit_support(self, N=144):
|
||||
h = self.local_height
|
||||
return sum([self.BIP9(h-i, 2) for i in range(N)])*10000/N/100.
|
||||
|
||||
def get_target(self, index):
|
||||
if bitcoin.NetworkConstants.TESTNET:
|
||||
return 0, 0
|
||||
|
|
|
@ -123,7 +123,7 @@ class Commands:
|
|||
return ' '.join(sorted(known_commands.keys()))
|
||||
|
||||
@command('')
|
||||
def create(self, segwit=False):
|
||||
def create(self):
|
||||
"""Create a new wallet"""
|
||||
raise BaseException('Not a JSON-RPC command')
|
||||
|
||||
|
@ -159,10 +159,10 @@ class Commands:
|
|||
return True
|
||||
|
||||
@command('')
|
||||
def make_seed(self, nbits=132, entropy=1, language=None, segwit=False):
|
||||
def make_seed(self, nbits=132, entropy=1, language=None):
|
||||
"""Create a seed"""
|
||||
from .mnemonic import Mnemonic
|
||||
t = 'segwit' if segwit else 'standard'
|
||||
t = 'standard'
|
||||
s = Mnemonic(language).make_seed(t, nbits, custom_entropy=entropy)
|
||||
return s
|
||||
|
||||
|
@ -713,7 +713,6 @@ command_options = {
|
|||
'change_addr': ("-c", "Change address. Default is a spare address, or the source address if it's not in the wallet"),
|
||||
'nbits': (None, "Number of bits of entropy"),
|
||||
'entropy': (None, "Custom entropy"),
|
||||
'segwit': (None, "Create segwit seed"),
|
||||
'language': ("-L", "Default language for wordlist"),
|
||||
'privkey': (None, "Private key. Set to '?' to get a prompt."),
|
||||
'unsigned': ("-u", "Do not sign transaction"),
|
||||
|
|
|
@ -571,7 +571,7 @@ def bip39_is_checksum_valid(mnemonic):
|
|||
def from_bip39_seed(seed, passphrase, derivation):
|
||||
k = BIP32_KeyStore({})
|
||||
bip32_seed = bip39_to_seed(seed, passphrase)
|
||||
t = 'p2wpkh-p2sh' if derivation.startswith("m/49'") else 'standard' # bip43
|
||||
t = 'standard' # bip43
|
||||
k.add_xprv_from_seed(bip32_seed, t, derivation)
|
||||
return k
|
||||
|
||||
|
@ -681,17 +681,13 @@ def from_seed(seed, passphrase, is_p2sh):
|
|||
if t == 'old':
|
||||
keystore = Old_KeyStore({})
|
||||
keystore.add_seed(seed)
|
||||
elif t in ['standard', 'segwit']:
|
||||
elif t in ['standard']:
|
||||
keystore = BIP32_KeyStore({})
|
||||
keystore.add_seed(seed)
|
||||
keystore.passphrase = passphrase
|
||||
bip32_seed = Mnemonic.mnemonic_to_seed(seed, passphrase)
|
||||
if t == 'standard':
|
||||
der = "m/"
|
||||
xtype = 'standard'
|
||||
else:
|
||||
der = "m/1'/" if is_p2sh else "m/0'/"
|
||||
xtype = 'p2wsh' if is_p2sh else 'p2wpkh'
|
||||
der = "m/"
|
||||
xtype = 'standard'
|
||||
keystore.add_xprv_from_seed(bip32_seed, xtype, der)
|
||||
else:
|
||||
raise BaseException(t)
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
# Copyright (c) 2017 Pieter Wuille
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""Reference implementation for Bech32 and segwit addresses."""
|
||||
|
||||
|
||||
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
|
||||
|
||||
|
||||
def bech32_polymod(values):
|
||||
"""Internal function that computes the Bech32 checksum."""
|
||||
generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
|
||||
chk = 1
|
||||
for value in values:
|
||||
top = chk >> 25
|
||||
chk = (chk & 0x1ffffff) << 5 ^ value
|
||||
for i in range(5):
|
||||
chk ^= generator[i] if ((top >> i) & 1) else 0
|
||||
return chk
|
||||
|
||||
|
||||
def bech32_hrp_expand(hrp):
|
||||
"""Expand the HRP into values for checksum computation."""
|
||||
return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]
|
||||
|
||||
|
||||
def bech32_verify_checksum(hrp, data):
|
||||
"""Verify a checksum given HRP and converted data characters."""
|
||||
return bech32_polymod(bech32_hrp_expand(hrp) + data) == 1
|
||||
|
||||
|
||||
def bech32_create_checksum(hrp, data):
|
||||
"""Compute the checksum values given HRP and data."""
|
||||
values = bech32_hrp_expand(hrp) + data
|
||||
polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ 1
|
||||
return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
|
||||
|
||||
|
||||
def bech32_encode(hrp, data):
|
||||
"""Compute a Bech32 string given HRP and data values."""
|
||||
combined = data + bech32_create_checksum(hrp, data)
|
||||
return hrp + '1' + ''.join([CHARSET[d] for d in combined])
|
||||
|
||||
|
||||
def bech32_decode(bech):
|
||||
"""Validate a Bech32 string, and determine HRP and data."""
|
||||
if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or
|
||||
(bech.lower() != bech and bech.upper() != bech)):
|
||||
return (None, None)
|
||||
bech = bech.lower()
|
||||
pos = bech.rfind('1')
|
||||
if pos < 1 or pos + 7 > len(bech) or len(bech) > 90:
|
||||
return (None, None)
|
||||
if not all(x in CHARSET for x in bech[pos+1:]):
|
||||
return (None, None)
|
||||
hrp = bech[:pos]
|
||||
data = [CHARSET.find(x) for x in bech[pos+1:]]
|
||||
if not bech32_verify_checksum(hrp, data):
|
||||
return (None, None)
|
||||
return (hrp, data[:-6])
|
||||
|
||||
|
||||
def convertbits(data, frombits, tobits, pad=True):
|
||||
"""General power-of-2 base conversion."""
|
||||
acc = 0
|
||||
bits = 0
|
||||
ret = []
|
||||
maxv = (1 << tobits) - 1
|
||||
max_acc = (1 << (frombits + tobits - 1)) - 1
|
||||
for value in data:
|
||||
if value < 0 or (value >> frombits):
|
||||
return None
|
||||
acc = ((acc << frombits) | value) & max_acc
|
||||
bits += frombits
|
||||
while bits >= tobits:
|
||||
bits -= tobits
|
||||
ret.append((acc >> bits) & maxv)
|
||||
if pad:
|
||||
if bits:
|
||||
ret.append((acc << (tobits - bits)) & maxv)
|
||||
elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
|
||||
return None
|
||||
return ret
|
||||
|
||||
|
||||
def decode(hrp, addr):
|
||||
"""Decode a segwit address."""
|
||||
hrpgot, data = bech32_decode(addr)
|
||||
if hrpgot != hrp:
|
||||
return (None, None)
|
||||
decoded = convertbits(data[1:], 5, 8, False)
|
||||
if decoded is None or len(decoded) < 2 or len(decoded) > 40:
|
||||
return (None, None)
|
||||
if data[0] > 16:
|
||||
return (None, None)
|
||||
if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32:
|
||||
return (None, None)
|
||||
return (data[0], decoded)
|
||||
|
||||
|
||||
def encode(hrp, witver, witprog):
|
||||
"""Encode a segwit address."""
|
||||
ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5))
|
||||
assert decode(hrp, ret) is not (None, None)
|
||||
return ret
|
|
@ -399,7 +399,6 @@ class WalletStorage(PrintError):
|
|||
def convert_version_15(self):
|
||||
if not self._is_upgrade_method_needed(14, 14):
|
||||
return
|
||||
assert self.get('seed_type') != 'segwit' # unsupported derivation
|
||||
self.put('seed_version', 15)
|
||||
|
||||
def convert_version_16(self):
|
||||
|
@ -498,8 +497,6 @@ class WalletStorage(PrintError):
|
|||
seed_version = OLD_SEED_VERSION if len(self.get('master_public_key','')) == 128 else NEW_SEED_VERSION
|
||||
if seed_version > FINAL_SEED_VERSION:
|
||||
raise BaseException('This version of Electrum is too old to open this wallet')
|
||||
if seed_version==14 and self.get('seed_type') == 'segwit':
|
||||
self.raise_unsupported_version(seed_version)
|
||||
if seed_version >=12:
|
||||
return seed_version
|
||||
if seed_version not in [OLD_SEED_VERSION, NEW_SEED_VERSION]:
|
||||
|
|
|
@ -301,10 +301,7 @@ def parse_scriptSig(d, _bytes):
|
|||
match = [ opcodes.OP_PUSHDATA4 ]
|
||||
if match_decoded(decoded, match):
|
||||
item = decoded[0][1]
|
||||
if item[0] == 0:
|
||||
d['address'] = bitcoin.hash160_to_p2sh(bitcoin.hash_160(item))
|
||||
d['type'] = 'p2wpkh-p2sh' if len(item) == 22 else 'p2wsh-p2sh'
|
||||
else:
|
||||
if item[0] != 0:
|
||||
# payto_pubkey
|
||||
d['type'] = 'p2pk'
|
||||
d['address'] = "(pubkey)"
|
||||
|
@ -387,11 +384,6 @@ 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, hash_to_segwit_addr(decoded[1][1])
|
||||
|
||||
return TYPE_SCRIPT, bh2u(_bytes)
|
||||
|
||||
|
||||
|
@ -423,29 +415,6 @@ def parse_input(vds):
|
|||
return d
|
||||
|
||||
|
||||
def parse_witness(vds, txin):
|
||||
n = vds.read_compact_size()
|
||||
if n == 0:
|
||||
return
|
||||
if n == 0xffffffff:
|
||||
txin['value'] = vds.read_uint64()
|
||||
n = vds.read_compact_size()
|
||||
w = list(bh2u(vds.read_bytes(vds.read_compact_size())) for i in range(n))
|
||||
if txin['type'] == 'coinbase':
|
||||
pass
|
||||
elif n > 2:
|
||||
txin['signatures'] = parse_sig(w[1:-1])
|
||||
m, n, x_pubkeys, pubkeys, witnessScript = parse_redeemScript(bfh(w[-1]))
|
||||
txin['num_sig'] = m
|
||||
txin['x_pubkeys'] = x_pubkeys
|
||||
txin['pubkeys'] = pubkeys
|
||||
txin['witnessScript'] = witnessScript
|
||||
else:
|
||||
txin['num_sig'] = 1
|
||||
txin['x_pubkeys'] = [w[1]]
|
||||
txin['pubkeys'] = [safe_parse_pubkey(w[1])]
|
||||
txin['signatures'] = parse_sig([w[0]])
|
||||
|
||||
def parse_output(vds, i):
|
||||
d = {}
|
||||
d['value'] = vds.read_int64()
|
||||
|
@ -463,26 +432,9 @@ def deserialize(raw):
|
|||
start = vds.read_cursor
|
||||
d['version'] = vds.read_int32()
|
||||
n_vin = vds.read_compact_size()
|
||||
is_segwit = (n_vin == 0)
|
||||
if is_segwit:
|
||||
marker = vds.read_bytes(1)
|
||||
assert marker == b'\x01'
|
||||
n_vin = vds.read_compact_size()
|
||||
d['inputs'] = [parse_input(vds) for i in range(n_vin)]
|
||||
n_vout = vds.read_compact_size()
|
||||
d['outputs'] = [parse_output(vds, i) for i in range(n_vout)]
|
||||
if is_segwit:
|
||||
for i in range(n_vin):
|
||||
txin = d['inputs'][i]
|
||||
parse_witness(vds, txin)
|
||||
# segwit-native script
|
||||
if not txin.get('scriptSig'):
|
||||
if txin['num_sig'] == 1:
|
||||
txin['type'] = 'p2wpkh'
|
||||
txin['address'] = bitcoin.public_key_to_p2wpkh(bfh(txin['pubkeys'][0]))
|
||||
else:
|
||||
txin['type'] = 'p2wsh'
|
||||
txin['address'] = bitcoin.script_to_p2wsh(txin['witnessScript'])
|
||||
d['lockTime'] = vds.read_uint32()
|
||||
return d
|
||||
|
||||
|
@ -661,30 +613,6 @@ class Transaction:
|
|||
sig_list = [sig if sig else NO_SIGNATURE for sig in x_signatures]
|
||||
return pk_list, sig_list
|
||||
|
||||
@classmethod
|
||||
def serialize_witness(self, txin, estimate_size=False):
|
||||
add_w = lambda x: var_int(len(x)//2) + x
|
||||
if not self.is_segwit_input(txin):
|
||||
return '00'
|
||||
pubkeys, sig_list = self.get_siglist(txin, estimate_size)
|
||||
if txin['type'] in ['p2wpkh', 'p2wpkh-p2sh']:
|
||||
witness = var_int(2) + add_w(sig_list[0]) + add_w(pubkeys[0])
|
||||
elif txin['type'] in ['p2wsh', 'p2wsh-p2sh']:
|
||||
n = len(sig_list) + 2
|
||||
witness_script = multisig_script(pubkeys, txin['num_sig'])
|
||||
witness = var_int(n) + '00' + ''.join(add_w(x) for x in sig_list) + add_w(witness_script)
|
||||
else:
|
||||
raise BaseException('wrong txin type')
|
||||
if self.is_txin_complete(txin) or estimate_size:
|
||||
value_field = ''
|
||||
else:
|
||||
value_field = var_int(0xffffffff) + int_to_hex(txin['value'], 8)
|
||||
return value_field + witness
|
||||
|
||||
@classmethod
|
||||
def is_segwit_input(self, txin):
|
||||
return txin['type'] in ['p2wpkh', 'p2wpkh-p2sh', 'p2wsh', 'p2wsh-p2sh']
|
||||
|
||||
@classmethod
|
||||
def input_script(self, txin, estimate_size=False):
|
||||
_type = txin['type']
|
||||
|
@ -701,16 +629,6 @@ class Transaction:
|
|||
script += push_script(redeem_script)
|
||||
elif _type == 'p2pkh':
|
||||
script += push_script(pubkeys[0])
|
||||
elif _type in ['p2wpkh', 'p2wsh']:
|
||||
return ''
|
||||
elif _type == 'p2wpkh-p2sh':
|
||||
pubkey = safe_parse_pubkey(pubkeys[0])
|
||||
scriptSig = bitcoin.p2wpkh_nested_script(pubkey)
|
||||
return push_script(scriptSig)
|
||||
elif _type == 'p2wsh-p2sh':
|
||||
witness_script = self.get_preimage_script(txin)
|
||||
scriptSig = bitcoin.p2wsh_nested_script(witness_script)
|
||||
return push_script(scriptSig)
|
||||
elif _type == 'address':
|
||||
script += push_script(pubkeys[0])
|
||||
elif _type == 'unknown':
|
||||
|
@ -726,16 +644,11 @@ class Transaction:
|
|||
|
||||
@classmethod
|
||||
def get_preimage_script(self, txin):
|
||||
# only for non-segwit
|
||||
if txin['type'] == 'p2pkh':
|
||||
return bitcoin.address_to_script(txin['address'])
|
||||
elif txin['type'] in ['p2sh', 'p2wsh', 'p2wsh-p2sh']:
|
||||
elif txin['type'] in ['p2sh']:
|
||||
pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin)
|
||||
return multisig_script(pubkeys, txin['num_sig'])
|
||||
elif txin['type'] in ['p2wpkh', 'p2wpkh-p2sh']:
|
||||
pubkey = txin['pubkeys'][0]
|
||||
pkh = bh2u(bitcoin.hash_160(bfh(pubkey)))
|
||||
return '76a9' + push_script(pkh) + '88ac'
|
||||
elif txin['type'] == 'p2pk':
|
||||
pubkey = txin['pubkeys'][0]
|
||||
return bitcoin.public_key_to_p2pk_script(pubkey)
|
||||
|
@ -782,53 +695,28 @@ class Transaction:
|
|||
outputs = self.outputs()
|
||||
txin = inputs[i]
|
||||
# TODO: py3 hex
|
||||
if self.is_segwit_input(txin):
|
||||
hashPrevouts = bh2u(Hash(bfh(''.join(self.serialize_outpoint(txin) for txin in inputs))))
|
||||
hashSequence = bh2u(Hash(bfh(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs))))
|
||||
hashOutputs = bh2u(Hash(bfh(''.join(self.serialize_output(o) for o in outputs))))
|
||||
outpoint = self.serialize_outpoint(txin)
|
||||
preimage_script = self.get_preimage_script(txin)
|
||||
scriptCode = var_int(len(preimage_script) // 2) + preimage_script
|
||||
amount = int_to_hex(txin['value'], 8)
|
||||
nSequence = int_to_hex(txin.get('sequence', 0xffffffff - 1), 4)
|
||||
preimage = nVersion + hashPrevouts + hashSequence + outpoint + scriptCode + amount + nSequence + hashOutputs + nLocktime + nHashType
|
||||
else:
|
||||
txins = var_int(len(inputs)) + ''.join(self.serialize_input(txin, self.get_preimage_script(txin) if i==k else '') for k, txin in enumerate(inputs))
|
||||
txouts = var_int(len(outputs)) + ''.join(self.serialize_output(o) for o in outputs)
|
||||
preimage = nVersion + txins + txouts + nLocktime + nHashType
|
||||
txins = var_int(len(inputs)) + ''.join(self.serialize_input(txin, self.get_preimage_script(txin) if i==k else '') for k, txin in enumerate(inputs))
|
||||
txouts = var_int(len(outputs)) + ''.join(self.serialize_output(o) for o in outputs)
|
||||
preimage = nVersion + txins + txouts + nLocktime + nHashType
|
||||
return preimage
|
||||
|
||||
def is_segwit(self):
|
||||
return any(self.is_segwit_input(x) for x in self.inputs())
|
||||
|
||||
def serialize(self, estimate_size=False, witness=True):
|
||||
def serialize(self, estimate_size=False):
|
||||
nVersion = int_to_hex(self.version, 4)
|
||||
nLocktime = int_to_hex(self.locktime, 4)
|
||||
inputs = self.inputs()
|
||||
outputs = self.outputs()
|
||||
txins = var_int(len(inputs)) + ''.join(self.serialize_input(txin, self.input_script(txin, estimate_size)) for txin in inputs)
|
||||
txouts = var_int(len(outputs)) + ''.join(self.serialize_output(o) for o in outputs)
|
||||
if witness and self.is_segwit():
|
||||
marker = '00'
|
||||
flag = '01'
|
||||
witness = ''.join(self.serialize_witness(x, estimate_size) for x in inputs)
|
||||
return nVersion + marker + flag + txins + txouts + witness + nLocktime
|
||||
else:
|
||||
return nVersion + txins + txouts + nLocktime
|
||||
return nVersion + txins + txouts + nLocktime
|
||||
|
||||
def hash(self):
|
||||
print("warning: deprecated tx.hash()")
|
||||
return self.txid()
|
||||
|
||||
def txid(self):
|
||||
all_segwit = all(self.is_segwit_input(x) for x in self.inputs())
|
||||
if not all_segwit and not self.is_complete():
|
||||
if not self.is_complete():
|
||||
return None
|
||||
ser = self.serialize(witness=False)
|
||||
return bh2u(Hash(bfh(ser))[::-1])
|
||||
|
||||
def wtxid(self):
|
||||
ser = self.serialize(witness=True)
|
||||
ser = self.serialize()
|
||||
return bh2u(Hash(bfh(ser))[::-1])
|
||||
|
||||
def add_inputs(self, inputs):
|
||||
|
@ -867,15 +755,7 @@ class Transaction:
|
|||
'''Return an estimate of serialized input weight in weight units.'''
|
||||
script = cls.input_script(txin, True)
|
||||
input_size = len(cls.serialize_input(txin, script)) // 2
|
||||
|
||||
# note: we should actually branch based on tx.is_segwit()
|
||||
# only if none of the inputs have a witness, is the size actually 0
|
||||
if cls.is_segwit_input(txin):
|
||||
witness_size = len(cls.serialize_witness(txin, True)) // 2
|
||||
else:
|
||||
witness_size = 0
|
||||
|
||||
return 4 * input_size + witness_size
|
||||
return 4 * input_size
|
||||
|
||||
@classmethod
|
||||
def virtual_size_from_weight(cls, weight):
|
||||
|
@ -885,19 +765,9 @@ class Transaction:
|
|||
"""Return an estimated total transaction size in bytes."""
|
||||
return len(self.serialize(True)) // 2 if not self.is_complete() or self.raw is None else len(self.raw) // 2 # ASCII hex string
|
||||
|
||||
def estimated_witness_size(self):
|
||||
"""Return an estimate of witness size in bytes."""
|
||||
if not self.is_segwit():
|
||||
return 0
|
||||
inputs = self.inputs()
|
||||
estimate = not self.is_complete()
|
||||
witness = ''.join(self.serialize_witness(x, estimate) for x in inputs)
|
||||
witness_size = len(witness) // 2 + 2 # include marker and flag
|
||||
return witness_size
|
||||
|
||||
def estimated_base_size(self):
|
||||
"""Return an estimated base transaction size in bytes."""
|
||||
return self.estimated_total_size() - self.estimated_witness_size()
|
||||
return self.estimated_total_size()
|
||||
|
||||
def estimated_weight(self):
|
||||
"""Return an estimate of transaction weight."""
|
||||
|
|
|
@ -4,13 +4,10 @@ PROTOCOL_VERSION = '1.1' # protocol version requested
|
|||
# The hash of the mnemonic seed must begin with this
|
||||
SEED_PREFIX = '01' # Standard wallet
|
||||
SEED_PREFIX_2FA = '101' # Two-factor authentication
|
||||
SEED_PREFIX_SW = '100' # Segwit wallet
|
||||
|
||||
|
||||
def seed_prefix(seed_type):
|
||||
if seed_type == 'standard':
|
||||
return SEED_PREFIX
|
||||
elif seed_type == 'segwit':
|
||||
return SEED_PREFIX_SW
|
||||
elif seed_type == '2fa':
|
||||
return SEED_PREFIX_2FA
|
||||
|
|
|
@ -346,7 +346,7 @@ class Abstract_Wallet(PrintError):
|
|||
return []
|
||||
index = self.get_address_index(address)
|
||||
pk, compressed = self.keystore.get_private_key(index, password)
|
||||
if self.txin_type in ['p2sh', 'p2wsh', 'p2wsh-p2sh']:
|
||||
if self.txin_type in ['p2sh']:
|
||||
pubkeys = self.get_public_keys(address)
|
||||
redeem_script = self.pubkeys_to_redeem_script(pubkeys)
|
||||
else:
|
||||
|
@ -1096,12 +1096,6 @@ class Abstract_Wallet(PrintError):
|
|||
address = txin['address']
|
||||
if self.is_mine(address):
|
||||
txin['type'] = self.get_txin_type(address)
|
||||
# segwit needs value to sign
|
||||
if txin.get('value') is None and Transaction.is_segwit_input(txin):
|
||||
received, spent = self.get_addr_io(address)
|
||||
item = received.get(txin['prevout_hash']+':%d'%txin['prevout_n'])
|
||||
tx_height, value, is_cb = item
|
||||
txin['value'] = value
|
||||
self.add_input_sig_info(txin, address)
|
||||
|
||||
def can_sign(self, tx):
|
||||
|
@ -1519,11 +1513,11 @@ class Imported_Wallet(Simple_Wallet):
|
|||
txin_type, pubkey = self.keystore.import_privkey(sec, pw)
|
||||
except Exception:
|
||||
raise BaseException('Invalid private key', sec)
|
||||
if txin_type in ['p2pkh', 'p2wpkh', 'p2wpkh-p2sh']:
|
||||
if txin_type in ['p2pkh']:
|
||||
if redeem_script is not None:
|
||||
raise BaseException('Cannot use redeem script with', txin_type, sec)
|
||||
addr = bitcoin.pubkey_to_address(txin_type, pubkey)
|
||||
elif txin_type in ['p2sh', 'p2wsh', 'p2wsh-p2sh']:
|
||||
elif txin_type in ['p2sh']:
|
||||
if redeem_script is None:
|
||||
raise BaseException('Redeem script required for', txin_type, sec)
|
||||
addr = bitcoin.redeem_script_to_address(txin_type, redeem_script)
|
||||
|
@ -1552,7 +1546,7 @@ class Imported_Wallet(Simple_Wallet):
|
|||
txin['x_pubkeys'] = [x_pubkey]
|
||||
txin['signatures'] = [None]
|
||||
return
|
||||
if txin['type'] in ['p2pkh', 'p2wpkh', 'p2wpkh-p2sh']:
|
||||
if txin['type'] in ['p2pkh']:
|
||||
pubkey = self.addresses[address]['pubkey']
|
||||
txin['num_sig'] = 1
|
||||
txin['x_pubkeys'] = [pubkey]
|
||||
|
|
Loading…
Reference in New Issue