mirror of
https://github.com/JoinMarket-Org/joinmarket-clientserver.git
synced 2026-08-13 12:33:40 +02:00
Add support for spending timelocked UTXOs
The cryptoengine class BTC_Timelocked_P2WSH now implements sign_transaction() which can be used to spend timelocked UTXOs. FidelityBondMixin.is_timelocked_path() is now used outside the class so its leading underscore has been removed.
This commit is contained in:
parent
762b1f644d
commit
a0a0d28f4e
3 changed files with 38 additions and 12 deletions
|
|
@ -332,14 +332,19 @@ class BTC_Timelocked_P2WSH(BTCEngine):
|
|||
return btc.bin_to_b58check(priv, cls.WIF_PREFIX)
|
||||
|
||||
@classmethod
|
||||
def sign_transaction(cls, tx, index, privkey, amount,
|
||||
def sign_transaction(cls, tx, index, privkey_locktime, amount,
|
||||
hashcode=btc.SIGHASH_ALL, **kwargs):
|
||||
raise Exception("not implemented yet")
|
||||
assert amount is not None
|
||||
|
||||
@classmethod
|
||||
def sign_transaction(cls, tx, index, privkey, amount,
|
||||
hashcode=btc.SIGHASH_ALL, **kwargs):
|
||||
raise RuntimeError("Cannot spend from watch-only wallets")
|
||||
privkey, locktime = privkey_locktime
|
||||
privkey = hexlify(privkey).decode()
|
||||
pubkey = btc.privkey_to_pubkey(privkey)
|
||||
pubkey = unhexlify(pubkey)
|
||||
redeem_script = cls.pubkey_to_script_code((pubkey, locktime))
|
||||
tx = btc.serialize(tx)
|
||||
sig = btc.get_p2sh_signature(tx, index, redeem_script, privkey,
|
||||
amount)
|
||||
return btc.apply_freeze_signature(tx, index, redeem_script, sig)
|
||||
|
||||
class BTC_Watchonly_Timelocked_P2WSH(BTC_Timelocked_P2WSH):
|
||||
|
||||
|
|
@ -368,7 +373,7 @@ class BTC_Watchonly_Timelocked_P2WSH(BTC_Timelocked_P2WSH):
|
|||
@classmethod
|
||||
def sign_transaction(cls, tx, index, privkey, amount,
|
||||
hashcode=btc.SIGHASH_ALL, **kwargs):
|
||||
raise Exception("not implemented yet")
|
||||
raise RuntimeError("Cannot spend from watch-only wallets")
|
||||
|
||||
class BTC_Watchonly_P2SH_P2WPKH(BTC_P2SH_P2WPKH):
|
||||
|
||||
|
|
@ -392,6 +397,11 @@ class BTC_Watchonly_P2SH_P2WPKH(BTC_P2SH_P2WPKH):
|
|||
return super(BTC_Watchonly_P2SH_P2WPKH, cls).derive_bip32_pub_export(
|
||||
master_key, BTC_Watchonly_Timelocked_P2WSH.get_watchonly_path(path))
|
||||
|
||||
@classmethod
|
||||
def sign_transaction(cls, tx, index, privkey, amount,
|
||||
hashcode=btc.SIGHASH_ALL, **kwargs):
|
||||
raise RuntimeError("Cannot spend from watch-only wallets")
|
||||
|
||||
ENGINES = {
|
||||
TYPE_P2PKH: BTC_P2PKH,
|
||||
TYPE_P2SH_P2WPKH: BTC_P2SH_P2WPKH,
|
||||
|
|
|
|||
|
|
@ -117,12 +117,28 @@ def direct_send(wallet_service, amount, mixdepth, destination, answeryes=False,
|
|||
change_addr = wallet_service.get_internal_addr(mixdepth)
|
||||
outs.append({"value": changeval, "address": change_addr})
|
||||
|
||||
#compute transaction locktime, has special case for spending timelocked coins
|
||||
tx_locktime = compute_tx_locktime()
|
||||
if mixdepth == FidelityBondMixin.FIDELITY_BOND_MIXDEPTH and \
|
||||
isinstance(wallet_service.wallet, FidelityBondMixin):
|
||||
for outpoint, utxo in utxos.items():
|
||||
path = wallet_service.script_to_path(
|
||||
wallet_service.addr_to_script(utxo["address"]))
|
||||
if not FidelityBondMixin.is_timelocked_path(path):
|
||||
continue
|
||||
path_locktime = path[-1]
|
||||
tx_locktime = max(tx_locktime, path_locktime+1)
|
||||
#compute_tx_locktime() gives a locktime in terms of block height
|
||||
#timelocked addresses use unix time instead
|
||||
#OP_CHECKLOCKTIMEVERIFY can only compare like with like, so we
|
||||
#must use unix time as the transaction locktime
|
||||
|
||||
#Now ready to construct transaction
|
||||
log.info("Using a fee of : " + amount_to_str(fee_est) + ".")
|
||||
if amount != 0:
|
||||
log.info("Using a change value of: " + amount_to_str(changeval) + ".")
|
||||
txsigned = sign_tx(wallet_service, make_shuffled_tx(
|
||||
list(utxos.keys()), outs, False, 2, compute_tx_locktime()), utxos)
|
||||
list(utxos.keys()), outs, False, 2, tx_locktime), utxos)
|
||||
log.info("Got signed transaction:\n")
|
||||
log.info(pformat(txsigned))
|
||||
tx = serialize(txsigned)
|
||||
|
|
|
|||
|
|
@ -1694,7 +1694,7 @@ class FidelityBondMixin(object):
|
|||
return timenumber
|
||||
|
||||
@classmethod
|
||||
def _is_timelocked_path(cls, path):
|
||||
def is_timelocked_path(cls, path):
|
||||
return len(path) > 4 and path[4] == cls.BIP32_TIMELOCK_ID
|
||||
|
||||
def get_xpub_from_fidelity_bond_master_pub_key(cls, mpk):
|
||||
|
|
@ -1737,7 +1737,7 @@ class FidelityBondMixin(object):
|
|||
return (cls.BIP32_EXT_ID, cls.BIP32_INT_ID, cls.BIP32_TIMELOCK_ID, cls.BIP32_BURN_ID)
|
||||
|
||||
def _get_priv_from_path(self, path):
|
||||
if self._is_timelocked_path(path):
|
||||
if self.is_timelocked_path(path):
|
||||
key_path = path[:-1]
|
||||
locktime = path[-1]
|
||||
engine = self._TIMELOCK_ENGINE
|
||||
|
|
@ -1766,7 +1766,7 @@ class FidelityBondMixin(object):
|
|||
refering to the pubkey plus the timelock value which together are needed to create the address
|
||||
"""
|
||||
def get_path_repr(self, path):
|
||||
if self._is_timelocked_path(path) and len(path) == 7:
|
||||
if self.is_timelocked_path(path) and len(path) == 7:
|
||||
return super(FidelityBondMixin, self).get_path_repr(path[:-1]) +\
|
||||
":" + str(path[-1])
|
||||
else:
|
||||
|
|
@ -1785,7 +1785,7 @@ class FidelityBondMixin(object):
|
|||
))
|
||||
|
||||
def get_details(self, path):
|
||||
if self._is_timelocked_path(path):
|
||||
if self.is_timelocked_path(path):
|
||||
return self._get_mixdepth_from_path(path), path[-3], path[-2]
|
||||
else:
|
||||
return super(FidelityBondMixin, self).get_details(path)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue