support native segwit transactions
This commit is contained in:
@@ -357,7 +357,7 @@ class BaseWizard(object):
|
|||||||
|
|
||||||
def create_seed(self):
|
def create_seed(self):
|
||||||
from . import mnemonic
|
from . import mnemonic
|
||||||
self.seed_type = 'segwit' if bitcoin.TESTNET and self.config.get('segwit') else 'standard'
|
self.seed_type = 'segwit' if self.config.get('segwit') else 'standard'
|
||||||
seed = mnemonic.Mnemonic('en').make_seed(self.seed_type)
|
seed = mnemonic.Mnemonic('en').make_seed(self.seed_type)
|
||||||
self.opt_bip39 = False
|
self.opt_bip39 = False
|
||||||
f = lambda x: self.request_passphrase(seed, x)
|
f = lambda x: self.request_passphrase(seed, x)
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ def seed_type(x):
|
|||||||
return 'old'
|
return 'old'
|
||||||
elif is_new_seed(x):
|
elif is_new_seed(x):
|
||||||
return 'standard'
|
return 'standard'
|
||||||
elif TESTNET and is_new_seed(x, version.SEED_PREFIX_SW):
|
elif is_new_seed(x, version.SEED_PREFIX_SW):
|
||||||
return 'segwit'
|
return 'segwit'
|
||||||
elif is_new_seed(x, version.SEED_PREFIX_2FA):
|
elif is_new_seed(x, version.SEED_PREFIX_2FA):
|
||||||
return '2fa'
|
return '2fa'
|
||||||
@@ -307,16 +307,21 @@ def b58_address_to_hash160(addr):
|
|||||||
def hash160_to_p2pkh(h160):
|
def hash160_to_p2pkh(h160):
|
||||||
return hash160_to_b58_address(h160, ADDRTYPE_P2PKH)
|
return hash160_to_b58_address(h160, ADDRTYPE_P2PKH)
|
||||||
|
|
||||||
|
|
||||||
def hash160_to_p2sh(h160):
|
def hash160_to_p2sh(h160):
|
||||||
return hash160_to_b58_address(h160, ADDRTYPE_P2SH)
|
return hash160_to_b58_address(h160, ADDRTYPE_P2SH)
|
||||||
|
|
||||||
|
|
||||||
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 hash_to_segwit_addr(h):
|
||||||
return segwit_addr.encode(SEGWIT_HRP, 0, h160)
|
return segwit_addr.encode(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 address_to_script(addr):
|
def address_to_script(addr):
|
||||||
if is_segwit_address(addr):
|
if is_segwit_address(addr):
|
||||||
@@ -838,7 +843,7 @@ def deserialize_xkey(xkey, prv):
|
|||||||
c = xkey[13:13+32]
|
c = xkey[13:13+32]
|
||||||
header = XPRV_HEADER if prv else XPUB_HEADER
|
header = XPRV_HEADER if prv else XPUB_HEADER
|
||||||
xtype = int('0x' + bh2u(xkey[0:4]), 16) - header
|
xtype = int('0x' + bh2u(xkey[0:4]), 16) - header
|
||||||
if xtype not in ([0, 1] if TESTNET else [0]):
|
if xtype not in [0, 1]:
|
||||||
raise BaseException('Invalid header')
|
raise BaseException('Invalid header')
|
||||||
n = 33 if prv else 32
|
n = 33 if prv else 32
|
||||||
K_or_k = xkey[13+n:]
|
K_or_k = xkey[13+n:]
|
||||||
|
|||||||
@@ -163,7 +163,8 @@ class Commands:
|
|||||||
def make_seed(self, nbits=132, entropy=1, language=None):
|
def make_seed(self, nbits=132, entropy=1, language=None):
|
||||||
"""Create a seed"""
|
"""Create a seed"""
|
||||||
from .mnemonic import Mnemonic
|
from .mnemonic import Mnemonic
|
||||||
s = Mnemonic(language).make_seed('standard', nbits, custom_entropy=entropy)
|
t = 'segwit' if self.config.get('segwit') else 'standard'
|
||||||
|
s = Mnemonic(language).make_seed(t, nbits, custom_entropy=entropy)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
@command('')
|
@command('')
|
||||||
|
|||||||
@@ -701,6 +701,8 @@ def from_seed(seed, passphrase):
|
|||||||
bip32_seed = Mnemonic.mnemonic_to_seed(seed, passphrase)
|
bip32_seed = Mnemonic.mnemonic_to_seed(seed, passphrase)
|
||||||
xtype = 0 if t == 'standard' else 1
|
xtype = 0 if t == 'standard' else 1
|
||||||
keystore.add_xprv_from_seed(bip32_seed, xtype, "m/")
|
keystore.add_xprv_from_seed(bip32_seed, xtype, "m/")
|
||||||
|
else:
|
||||||
|
raise BaseException(t)
|
||||||
return keystore
|
return keystore
|
||||||
|
|
||||||
def from_private_key_list(text):
|
def from_private_key_list(text):
|
||||||
|
|||||||
@@ -116,6 +116,19 @@ class BCDataStream(object):
|
|||||||
def write_int64(self, val): return self._write_num('<q', val)
|
def write_int64(self, val): return self._write_num('<q', val)
|
||||||
def write_uint64(self, val): return self._write_num('<Q', val)
|
def write_uint64(self, val): return self._write_num('<Q', val)
|
||||||
|
|
||||||
|
def read_push_size(self):
|
||||||
|
size = self.input[self.read_cursor]
|
||||||
|
self.read_cursor += 1
|
||||||
|
if size < 0x4c:
|
||||||
|
return size
|
||||||
|
if size == 0x4c:
|
||||||
|
nsize = self.read_bytes(1)[0]
|
||||||
|
elif size == 0x4d:
|
||||||
|
nsize = self._read_num('<H')
|
||||||
|
elif size == 0x4e:
|
||||||
|
nsize = self._read_num('<I')
|
||||||
|
return nsize
|
||||||
|
|
||||||
def read_compact_size(self):
|
def read_compact_size(self):
|
||||||
size = self.input[self.read_cursor]
|
size = self.input[self.read_cursor]
|
||||||
self.read_cursor += 1
|
self.read_cursor += 1
|
||||||
@@ -309,9 +322,6 @@ def parse_scriptSig(d, _bytes):
|
|||||||
d['address'] = bitcoin.hash160_to_p2sh(bitcoin.hash_160(item))
|
d['address'] = bitcoin.hash160_to_p2sh(bitcoin.hash_160(item))
|
||||||
d['type'] = 'p2wpkh-p2sh'
|
d['type'] = 'p2wpkh-p2sh'
|
||||||
d['redeemScript'] = redeemScript
|
d['redeemScript'] = redeemScript
|
||||||
d['x_pubkeys'] = ["(witness)"]
|
|
||||||
d['pubkeys'] = ["(witness)"]
|
|
||||||
d['signatures'] = ['(witness)']
|
|
||||||
d['num_sig'] = 1
|
d['num_sig'] = 1
|
||||||
else:
|
else:
|
||||||
# payto_pubkey
|
# payto_pubkey
|
||||||
@@ -350,7 +360,19 @@ def parse_scriptSig(d, _bytes):
|
|||||||
print_error("cannot find address in input script", bh2u(_bytes))
|
print_error("cannot find address in input script", bh2u(_bytes))
|
||||||
return
|
return
|
||||||
x_sig = [bh2u(x[1]) for x in decoded[1:-1]]
|
x_sig = [bh2u(x[1]) for x in decoded[1:-1]]
|
||||||
dec2 = [ x for x in script_GetOp(decoded[-1][1]) ]
|
m, n, x_pubkeys, pubkeys, redeemScript = parse_redeemScript(decoded[-1][1])
|
||||||
|
# write result in d
|
||||||
|
d['type'] = 'p2sh'
|
||||||
|
d['num_sig'] = m
|
||||||
|
d['signatures'] = parse_sig(x_sig)
|
||||||
|
d['x_pubkeys'] = x_pubkeys
|
||||||
|
d['pubkeys'] = pubkeys
|
||||||
|
d['redeemScript'] = redeemScript
|
||||||
|
d['address'] = hash160_to_p2sh(hash_160(bfh(redeemScript)))
|
||||||
|
|
||||||
|
|
||||||
|
def parse_redeemScript(s):
|
||||||
|
dec2 = [ x for x in script_GetOp(s) ]
|
||||||
m = dec2[0][0] - opcodes.OP_1 + 1
|
m = dec2[0][0] - opcodes.OP_1 + 1
|
||||||
n = dec2[-2][0] - opcodes.OP_1 + 1
|
n = dec2[-2][0] - opcodes.OP_1 + 1
|
||||||
op_m = opcodes.OP_1 + m - 1
|
op_m = opcodes.OP_1 + m - 1
|
||||||
@@ -362,15 +384,7 @@ def parse_scriptSig(d, _bytes):
|
|||||||
x_pubkeys = [bh2u(x[1]) for x in dec2[1:-2]]
|
x_pubkeys = [bh2u(x[1]) for x in dec2[1:-2]]
|
||||||
pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys]
|
pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys]
|
||||||
redeemScript = multisig_script(pubkeys, m)
|
redeemScript = multisig_script(pubkeys, m)
|
||||||
# write result in d
|
return m, n, x_pubkeys, pubkeys, redeemScript
|
||||||
d['type'] = 'p2sh'
|
|
||||||
d['num_sig'] = m
|
|
||||||
d['signatures'] = parse_sig(x_sig)
|
|
||||||
d['x_pubkeys'] = x_pubkeys
|
|
||||||
d['pubkeys'] = pubkeys
|
|
||||||
d['redeemScript'] = redeemScript
|
|
||||||
d['address'] = hash160_to_p2sh(hash_160(bfh(redeemScript)))
|
|
||||||
|
|
||||||
|
|
||||||
def get_address_from_output_script(_bytes):
|
def get_address_from_output_script(_bytes):
|
||||||
decoded = [x for x in script_GetOp(_bytes)]
|
decoded = [x for x in script_GetOp(_bytes)]
|
||||||
@@ -395,7 +409,7 @@ def get_address_from_output_script(_bytes):
|
|||||||
# segwit address
|
# segwit address
|
||||||
match = [ opcodes.OP_0, opcodes.OP_PUSHDATA4 ]
|
match = [ opcodes.OP_0, opcodes.OP_PUSHDATA4 ]
|
||||||
if match_decoded(decoded, match):
|
if match_decoded(decoded, match):
|
||||||
return TYPE_ADDRESS, hash160_to_segwit_addr(decoded[1][1])
|
return TYPE_ADDRESS, hash_to_segwit_addr(decoded[1][1])
|
||||||
|
|
||||||
return TYPE_SCRIPT, bh2u(_bytes)
|
return TYPE_SCRIPT, bh2u(_bytes)
|
||||||
|
|
||||||
@@ -406,7 +420,6 @@ def parse_input(vds):
|
|||||||
prevout_n = vds.read_uint32()
|
prevout_n = vds.read_uint32()
|
||||||
scriptSig = vds.read_bytes(vds.read_compact_size())
|
scriptSig = vds.read_bytes(vds.read_compact_size())
|
||||||
sequence = vds.read_uint32()
|
sequence = vds.read_uint32()
|
||||||
d['scriptSig'] = bh2u(scriptSig)
|
|
||||||
d['prevout_hash'] = prevout_hash
|
d['prevout_hash'] = prevout_hash
|
||||||
d['prevout_n'] = prevout_n
|
d['prevout_n'] = prevout_n
|
||||||
d['sequence'] = sequence
|
d['sequence'] = sequence
|
||||||
@@ -420,12 +433,30 @@ def parse_input(vds):
|
|||||||
d['type'] = 'unknown'
|
d['type'] = 'unknown'
|
||||||
d['num_sig'] = 0
|
d['num_sig'] = 0
|
||||||
if scriptSig:
|
if scriptSig:
|
||||||
parse_scriptSig(d, scriptSig)
|
if len(scriptSig) == 8:
|
||||||
|
d['value'] = struct.unpack_from('<Q', scriptSig, 0)[0]
|
||||||
|
d['scriptSig'] = ''
|
||||||
|
else:
|
||||||
|
d['scriptSig'] = bh2u(scriptSig)
|
||||||
|
parse_scriptSig(d, scriptSig)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def parse_witness(vds):
|
|
||||||
|
def parse_witness(vds, txin):
|
||||||
n = vds.read_compact_size()
|
n = vds.read_compact_size()
|
||||||
return list(vds.read_bytes(vds.read_compact_size()) for i in range(n))
|
w = list(bh2u(vds.read_bytes(vds.read_push_size())) for i in range(n))
|
||||||
|
if n > 2:
|
||||||
|
txin['num_sig'] = n - 2
|
||||||
|
txin['signatures'] = parse_sig(w[1:-1])
|
||||||
|
m, n, x_pubkeys, pubkeys, witnessScript = parse_redeemScript(bfh(w[-1]))
|
||||||
|
txin['x_pubkeys'] = x_pubkeys
|
||||||
|
txin['pubkeys'] = pubkeys
|
||||||
|
txin['witnessScript'] = witnessScript
|
||||||
|
else:
|
||||||
|
txin['num_sig'] = 1
|
||||||
|
txin['pubkeys'] = [ w[-1] ]
|
||||||
|
txin['signatures'] = parse_sig([w[:-1]])
|
||||||
|
|
||||||
|
|
||||||
def parse_output(vds, i):
|
def parse_output(vds, i):
|
||||||
d = {}
|
d = {}
|
||||||
@@ -451,19 +482,24 @@ def deserialize(raw):
|
|||||||
n_vin = vds.read_compact_size()
|
n_vin = vds.read_compact_size()
|
||||||
d['inputs'] = [parse_input(vds) for i in range(n_vin)]
|
d['inputs'] = [parse_input(vds) for i in range(n_vin)]
|
||||||
n_vout = vds.read_compact_size()
|
n_vout = vds.read_compact_size()
|
||||||
d['outputs'] = [parse_output(vds,i) for i in range(n_vout)]
|
d['outputs'] = [parse_output(vds, i) for i in range(n_vout)]
|
||||||
if is_segwit:
|
if is_segwit:
|
||||||
d['witness'] = [parse_witness(vds) for i in range(n_vin)]
|
for i in range(n_vin):
|
||||||
|
txin = d['inputs'][i]
|
||||||
|
parse_witness(vds, txin)
|
||||||
|
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()
|
d['lockTime'] = vds.read_uint32()
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
# pay & redeem scripts
|
# pay & redeem scripts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def segwit_script(pubkey):
|
def segwit_script(pubkey):
|
||||||
pubkey = safe_parse_pubkey(pubkey)
|
pubkey = safe_parse_pubkey(pubkey)
|
||||||
pkh = bh2u(hash_160(bfh(pubkey)))
|
pkh = bh2u(hash_160(bfh(pubkey)))
|
||||||
@@ -536,12 +572,7 @@ class Transaction:
|
|||||||
for i, txin in enumerate(self.inputs()):
|
for i, txin in enumerate(self.inputs()):
|
||||||
pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin)
|
pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin)
|
||||||
sigs1 = txin.get('signatures')
|
sigs1 = txin.get('signatures')
|
||||||
if d.get('witness') is None:
|
sigs2 = d['inputs'][i].get('signatures')
|
||||||
sigs2 = d['inputs'][i].get('signatures')
|
|
||||||
else:
|
|
||||||
# signatures are in the witnesses. But the last item is
|
|
||||||
# the pubkey or the multisig script, so skip that.
|
|
||||||
sigs2 = d['witness'][i][:-1]
|
|
||||||
for sig in sigs2:
|
for sig in sigs2:
|
||||||
if sig in sigs1:
|
if sig in sigs1:
|
||||||
continue
|
continue
|
||||||
@@ -622,12 +653,18 @@ class Transaction:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def serialize_witness(self, txin):
|
def serialize_witness(self, txin):
|
||||||
pubkeys, sig_list = self.get_siglist(txin)
|
pubkeys, sig_list = self.get_siglist(txin)
|
||||||
n = len(pubkeys) + len(sig_list)
|
if txin['type'] in ['p2wpkh', 'p2wpkh-p2sh']:
|
||||||
return var_int(n) + ''.join(push_script(x) for x in sig_list) + ''.join(push_script(x) for x in pubkeys)
|
n = 2
|
||||||
|
return var_int(n) + push_script(sig_list[0]) + push_script(pubkeys[0])
|
||||||
|
elif txin['type'] in ['p2wsh', 'p2wsh-p2sh']:
|
||||||
|
n = len(sig_list) + 2
|
||||||
|
# fixme: witness script must be decided by wallet
|
||||||
|
witness_script = multisig_script(pubkeys, txin['num_sig'])
|
||||||
|
return var_int(n) + '00' + ''.join(push_script(x) for x in sig_list) + push_script(witness_script)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_segwit_input(self, txin):
|
def is_segwit_input(self, txin):
|
||||||
return txin['type'] in ['p2wpkh-p2sh']
|
return txin['type'] in ['p2wpkh', 'p2wpkh-p2sh', 'p2wsh', 'p2wsh-p2sh']
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def input_script(self, txin, estimate_size=False):
|
def input_script(self, txin, estimate_size=False):
|
||||||
@@ -645,7 +682,10 @@ class Transaction:
|
|||||||
script += push_script(redeem_script)
|
script += push_script(redeem_script)
|
||||||
elif _type == 'p2pkh':
|
elif _type == 'p2pkh':
|
||||||
script += push_script(pubkeys[0])
|
script += push_script(pubkeys[0])
|
||||||
elif _type == 'p2wpkh-p2sh':
|
elif _type in ['p2wpkh', 'p2wsh']:
|
||||||
|
# if it is not complete we store the value
|
||||||
|
return '' if self.is_txin_complete(txin) or estimate_size else int_to_hex(txin['value'], 8)
|
||||||
|
elif _type in ['p2wpkh-p2sh', 'p2wsh-p2sh']:
|
||||||
redeem_script = txin.get('redeemScript') or segwit_script(pubkeys[0])
|
redeem_script = txin.get('redeemScript') or segwit_script(pubkeys[0])
|
||||||
return push_script(redeem_script)
|
return push_script(redeem_script)
|
||||||
elif _type == 'address':
|
elif _type == 'address':
|
||||||
@@ -654,15 +694,22 @@ class Transaction:
|
|||||||
return txin['scriptSig']
|
return txin['scriptSig']
|
||||||
return script
|
return script
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_txin_complete(self, txin):
|
||||||
|
num_sig = txin.get('num_sig', 1)
|
||||||
|
x_signatures = txin['signatures']
|
||||||
|
signatures = list(filter(None, x_signatures))
|
||||||
|
return len(signatures) == num_sig
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_preimage_script(self, txin):
|
def get_preimage_script(self, txin):
|
||||||
# only for non-segwit
|
# only for non-segwit
|
||||||
if txin['type'] == 'p2pkh':
|
if txin['type'] == 'p2pkh':
|
||||||
return bitcoin.address_to_script(txin['address'])
|
return bitcoin.address_to_script(txin['address'])
|
||||||
elif txin['type'] == 'p2sh':
|
elif txin['type'] in ['p2sh', 'p2wsh']:
|
||||||
pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin)
|
pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin)
|
||||||
return multisig_script(pubkeys, txin['num_sig'])
|
return multisig_script(pubkeys, txin['num_sig'])
|
||||||
elif txin['type'] == 'p2wpkh-p2sh':
|
elif txin['type'] in ['p2wpkh', 'p2wpkh-p2sh']:
|
||||||
pubkey = txin['pubkeys'][0]
|
pubkey = txin['pubkeys'][0]
|
||||||
pkh = bh2u(bitcoin.hash_160(bfh(pubkey)))
|
pkh = bh2u(bitcoin.hash_160(bfh(pubkey)))
|
||||||
return '76a9' + push_script(pkh) + '88ac'
|
return '76a9' + push_script(pkh) + '88ac'
|
||||||
|
|||||||
@@ -1545,7 +1545,7 @@ class Simple_Wallet(Abstract_Wallet):
|
|||||||
def load_keystore(self):
|
def load_keystore(self):
|
||||||
self.keystore = load_keystore(self.storage, 'keystore')
|
self.keystore = load_keystore(self.storage, 'keystore')
|
||||||
self.is_segwit = self.keystore.is_segwit()
|
self.is_segwit = self.keystore.is_segwit()
|
||||||
self.txin_type = 'p2wpkh-p2sh' if self.is_segwit else 'p2pkh'
|
self.txin_type = 'p2wpkh' if self.is_segwit else 'p2pkh'
|
||||||
|
|
||||||
def get_pubkey(self, c, i):
|
def get_pubkey(self, c, i):
|
||||||
return self.derive_pubkeys(c, i)
|
return self.derive_pubkeys(c, i)
|
||||||
@@ -1635,15 +1635,6 @@ class Simple_Deterministic_Wallet(Deterministic_Wallet, Simple_Wallet):
|
|||||||
return addr
|
return addr
|
||||||
|
|
||||||
|
|
||||||
class P2SH:
|
|
||||||
|
|
||||||
def pubkeys_to_redeem_script(self, pubkeys):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def pubkeys_to_address(self, pubkey):
|
|
||||||
redeem_script = self.pubkeys_to_redeem_script(pubkey)
|
|
||||||
return bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
|
|
||||||
|
|
||||||
|
|
||||||
class Standard_Wallet(Simple_Deterministic_Wallet):
|
class Standard_Wallet(Simple_Deterministic_Wallet):
|
||||||
wallet_type = 'standard'
|
wallet_type = 'standard'
|
||||||
@@ -1653,19 +1644,20 @@ class Standard_Wallet(Simple_Deterministic_Wallet):
|
|||||||
return transaction.segwit_script(pubkey)
|
return transaction.segwit_script(pubkey)
|
||||||
|
|
||||||
def pubkeys_to_address(self, pubkey):
|
def pubkeys_to_address(self, pubkey):
|
||||||
if not self.is_segwit:
|
if self.txin_type == 'p2pkh':
|
||||||
return bitcoin.public_key_to_p2pkh(bfh(pubkey))
|
return bitcoin.public_key_to_p2pkh(bfh(pubkey))
|
||||||
elif bitcoin.TESTNET:
|
elif self.txin_type == 'p2wpkh':
|
||||||
|
return bitcoin.hash_to_segwit_addr(hash_160(bfh(pubkey)))
|
||||||
|
elif self.txin_type == 'p2wpkh-p2sh':
|
||||||
redeem_script = self.pubkeys_to_redeem_script(pubkey)
|
redeem_script = self.pubkeys_to_redeem_script(pubkey)
|
||||||
return bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
|
return bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
class Multisig_Wallet(Deterministic_Wallet, P2SH):
|
class Multisig_Wallet(Deterministic_Wallet):
|
||||||
# generic m of n
|
# generic m of n
|
||||||
gap_limit = 20
|
gap_limit = 20
|
||||||
txin_type = 'p2sh'
|
|
||||||
|
|
||||||
def __init__(self, storage):
|
def __init__(self, storage):
|
||||||
self.wallet_type = storage.get('wallet_type')
|
self.wallet_type = storage.get('wallet_type')
|
||||||
@@ -1675,9 +1667,19 @@ class Multisig_Wallet(Deterministic_Wallet, P2SH):
|
|||||||
def get_pubkeys(self, c, i):
|
def get_pubkeys(self, c, i):
|
||||||
return self.derive_pubkeys(c, i)
|
return self.derive_pubkeys(c, i)
|
||||||
|
|
||||||
def redeem_script(self, c, i):
|
def pubkeys_to_address(self, pubkey):
|
||||||
pubkeys = self.get_pubkeys(c, i)
|
if self.txin_type == 'p2sh':
|
||||||
return transaction.multisig_script(sorted(pubkeys), self.m)
|
redeem_script = self.pubkeys_to_redeem_script(pubkey)
|
||||||
|
return bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
|
||||||
|
elif self.txin_type == 'p2wsh':
|
||||||
|
witness_script = self.pubkeys_to_redeem_script(pubkey)
|
||||||
|
return bitcoin.script_to_p2wsh(witness_script)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
#def redeem_script(self, c, i):
|
||||||
|
# pubkeys = self.get_pubkeys(c, i)
|
||||||
|
# return transaction.multisig_script(sorted(pubkeys), self.m)
|
||||||
|
|
||||||
def pubkeys_to_redeem_script(self, pubkeys):
|
def pubkeys_to_redeem_script(self, pubkeys):
|
||||||
return transaction.multisig_script(sorted(pubkeys), self.m)
|
return transaction.multisig_script(sorted(pubkeys), self.m)
|
||||||
@@ -1691,6 +1693,8 @@ class Multisig_Wallet(Deterministic_Wallet, P2SH):
|
|||||||
name = 'x%d/'%(i+1)
|
name = 'x%d/'%(i+1)
|
||||||
self.keystores[name] = load_keystore(self.storage, name)
|
self.keystores[name] = load_keystore(self.storage, name)
|
||||||
self.keystore = self.keystores['x1/']
|
self.keystore = self.keystores['x1/']
|
||||||
|
self.is_segwit = self.keystore.is_segwit()
|
||||||
|
self.txin_type = 'p2wsh' if self.is_segwit else 'p2sh'
|
||||||
|
|
||||||
def save_keystore(self):
|
def save_keystore(self):
|
||||||
for name, k in self.keystores.items():
|
for name, k in self.keystores.items():
|
||||||
|
|||||||
Reference in New Issue
Block a user