account_deposit command added which accepts time locked TXs

This commit is contained in:
Lex Berezhny 2022-03-09 10:53:55 -05:00
parent 5777f3e15c
commit 0cbc514a8e
4 changed files with 65 additions and 20 deletions

View file

@ -28,6 +28,7 @@ from lbry.wallet import (
from lbry.wallet.dewies import dewies_to_lbc, lbc_to_dewies, dict_values_to_lbc
from lbry.wallet.constants import TXO_TYPES, CLAIM_TYPE_NAMES
from lbry.wallet.bip32 import PrivateKey
from lbry.crypto.base58 import Base58
from lbry import utils
from lbry.conf import Config, Setting, NOT_SET
@ -1872,6 +1873,48 @@ class Daemon(metaclass=JSONRPCServerType):
outputs=outputs, broadcast=broadcast
)
@requires("wallet")
async def jsonrpc_account_deposit(
self, txid, nout, redeem_script, private_key,
to_account=None, wallet_id=None, preview=False, blocking=False
):
"""
Spend a time locked transaction into your account.
Usage:
account_deposit <txid> <nout> <redeem_script> <private_key>
[<to_account> | --to_account=<to_account>]
[--wallet_id=<wallet_id>] [--preview] [--blocking]
Options:
--txid=<txid> : (str) id of the transaction
--nout=<nout> : (int) output number in the transaction
--redeem_script=<redeem_script> : (str) redeem script for output
--private_key=<private_key> : (str) private key to sign transaction
--to_account=<to_account> : (str) deposit to this account
--wallet_id=<wallet_id> : (str) limit operation to specific wallet.
--preview : (bool) do not broadcast the transaction
--blocking : (bool) wait until tx has synced
Returns: {Transaction}
"""
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
account = wallet.get_account_or_default(to_account)
other_tx = await self.wallet_manager.get_transaction(txid)
tx = await Transaction.spend_time_lock(
other_tx.outputs[nout], unhexlify(redeem_script), account
)
pk = PrivateKey.from_bytes(
account.ledger, Base58.decode_check(private_key)[1:-1]
)
tx.sign([account], {pk.address: pk})
if not preview:
await self.broadcast_or_release(tx, blocking)
self.component_manager.loop.create_task(self.analytics_manager.send_credits_sent())
else:
await self.ledger.release_tx(tx)
return tx
@requires(WALLET_COMPONENT)
def jsonrpc_account_send(self, amount, addresses, account_id=None, wallet_id=None, preview=False, blocking=False):
"""

View file

@ -215,6 +215,10 @@ class PrivateKey(_KeyBase):
private_key = cPrivateKey.from_int(key_int)
return cls(ledger, private_key, bytes((0,)*32), 0, 0)
@classmethod
def from_bytes(cls, ledger, key_bytes) -> 'PrivateKey':
return cls(ledger, cPrivateKey(key_bytes), bytes((0,)*32), 0, 0)
@cachedproperty
def private_key_bytes(self):
""" Return the serialized private key (no leading zero byte). """

View file

@ -860,7 +860,7 @@ class Transaction:
def signature_hash_type(hash_type):
return hash_type
async def sign(self, funding_accounts: Iterable['Account']):
async def sign(self, funding_accounts: Iterable['Account'], extra_keys: dict = None):
self._reset()
ledger, wallet = self.ensure_all_have_same_ledger_and_wallet(funding_accounts)
for i, txi in enumerate(self._inputs):
@ -870,6 +870,8 @@ class Transaction:
if txo_script.is_pay_pubkey_hash:
address = ledger.hash160_to_address(txo_script.values['pubkey_hash'])
private_key = await ledger.get_private_key_for_address(wallet, address)
if private_key is None and extra_keys:
private_key = extra_keys.get(address)
assert private_key is not None, 'Cannot find private key for signing output.'
tx = self._serialize_for_signature(i)
txi.script.values['signature'] = \
@ -944,14 +946,9 @@ class Transaction:
return cls.create([], [payment, data], funding_accounts, change_account)
@classmethod
def spend_time_lock(
cls, time_locked_txo: Output, amount: int, holding_address: str, script_source: str,
funding_accounts: List['Account'], change_account: 'Account'
):
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
txi = Input.spend_time_lock(time_locked_txo, unhexlify(script_source))
txo = Output.pay_pubkey_hash(amount, ledger.address_to_hash160(holding_address))
return cls.create([txi], [txo], funding_accounts, change_account)
def spend_time_lock(cls, time_locked_txo: Output, script: bytes, account: 'Account'):
txi = Input.spend_time_lock(time_locked_txo, script)
return cls.create([txi], [], [account], account, sign=False)
@property
def my_inputs(self):

View file

@ -1,9 +1,9 @@
from binascii import unhexlify
from lbry.testcase import CommandTestCase
from lbry.wallet.dewies import dewies_to_lbc, lbc_to_dewies
from lbry.wallet.dewies import dewies_to_lbc
from lbry.wallet.account import DeterministicChannelKeyManager
from lbry.wallet.transaction import Transaction, Input, Output
from lbry.crypto.base58 import Base58
def extract(d, keys):
@ -291,16 +291,17 @@ class AccountManagement(CommandTestCase):
self.assertTrue(channel3c.has_private_key)
async def test_time_locked_transactions(self):
from lbry.wallet.script import InputScript
address = await self.account.receiving.get_or_create_usable_address()
private_key = await self.ledger.get_private_key_for_address(self.wallet, address)
redeem = await self.blockchain.add_time_locked_address(210, address)
await self.assertBalance(self.account, '10.0')
tx = await self.daemon.jsonrpc_account_send('4.0', redeem['address'])
await self.confirm_tx(tx.id)
await self.blockchain.generate(10)
txi = Input.spend(tx.outputs[0])
txi.script.source = unhexlify(redeem['redeemScript'])
txo = Output.pay_pubkey_hash(lbc_to_dewies('3.9'), self.ledger.address_to_hash160(address))
new_tx = await Transaction.create([txi], [txo], self.wallet.accounts, self.wallet.default_account)
src = new_tx.raw
print(new_tx.raw)
await self.generate(510)
await self.assertBalance(self.account, '5.999877')
tx = await self.daemon.jsonrpc_account_deposit(
tx.id, 0, redeem['redeemScript'],
Base58.encode_check(self.ledger.private_key_to_wif(private_key.private_key_bytes))
)
await self.confirm_tx(tx.id)
await self.assertBalance(self.account, '9.999877')