This commit is contained in:
Lex Berezhny 2022-03-04 10:53:44 -05:00
parent 8cdcd770c0
commit 5777f3e15c
4 changed files with 56 additions and 2 deletions

View file

@ -679,6 +679,11 @@ class LBCWalletNode:
def get_raw_transaction(self, txid): def get_raw_transaction(self, txid):
return self._cli_cmnd('getrawtransaction', txid, '1') return self._cli_cmnd('getrawtransaction', txid, '1')
async def add_time_locked_address(self, height, address):
return json.loads(
await self._cli_cmnd('addtimelockedaddress', str(height), address)
)
class HubProcess(asyncio.SubprocessProtocol): class HubProcess(asyncio.SubprocessProtocol):
def __init__(self, ready, stopped): def __init__(self, ready, stopped):

View file

@ -17,6 +17,7 @@ OP_HASH160 = 0xa9
OP_EQUALVERIFY = 0x88 OP_EQUALVERIFY = 0x88
OP_CHECKSIG = 0xac OP_CHECKSIG = 0xac
OP_CHECKMULTISIG = 0xae OP_CHECKMULTISIG = 0xae
OP_CHECKLOCKTIMEVERIFY = 0xb1
OP_EQUAL = 0x87 OP_EQUAL = 0x87
OP_PUSHDATA1 = 0x4c OP_PUSHDATA1 = 0x4c
OP_PUSHDATA2 = 0x4d OP_PUSHDATA2 = 0x4d
@ -364,12 +365,18 @@ class InputScript(Script):
REDEEM_SCRIPT_HASH = Template('script_hash', ( REDEEM_SCRIPT_HASH = Template('script_hash', (
OP_0, PUSH_MANY('signatures'), PUSH_SUBSCRIPT('script', REDEEM_SCRIPT) OP_0, PUSH_MANY('signatures'), PUSH_SUBSCRIPT('script', REDEEM_SCRIPT)
)) ))
REDEEM_TIME_LOCK = Template('timelock', (
SMALL_INTEGER('height'), OP_CHECKLOCKTIMEVERIFY, OP_DROP,
# rest is identical to OutputScript.PAY_PUBKEY_HASH:
OP_DUP, OP_HASH160, PUSH_SINGLE('pubkey_hash'), OP_EQUALVERIFY, OP_CHECKSIG
))
templates = [ templates = [
REDEEM_PUBKEY, REDEEM_PUBKEY,
REDEEM_PUBKEY_HASH, REDEEM_PUBKEY_HASH,
REDEEM_SCRIPT_HASH, REDEEM_SCRIPT_HASH,
REDEEM_SCRIPT REDEEM_SCRIPT,
REDEEM_TIME_LOCK
] ]
@classmethod @classmethod
@ -394,6 +401,17 @@ class InputScript(Script):
'pubkeys_count': len(pubkeys) 'pubkeys_count': len(pubkeys)
}) })
@classmethod
def redeem_time_lock(cls, height, pubkey_hash):
return cls(template=cls.REDEEM_SCRIPT, values={
'height': height,
'pubkey_hash': pubkey_hash
})
@classmethod
def redeem_time_lock_from_script(cls, script: bytes):
return cls.from_source_with_template(script, cls.REDEEM_SCRIPT)
class OutputScript(Script): class OutputScript(Script):

View file

@ -145,6 +145,12 @@ class Input(InputOutput):
script = InputScript.redeem_pubkey_hash(cls.NULL_SIGNATURE, cls.NULL_PUBLIC_KEY) script = InputScript.redeem_pubkey_hash(cls.NULL_SIGNATURE, cls.NULL_PUBLIC_KEY)
return cls(txo.ref, script) return cls(txo.ref, script)
@classmethod
def spend_time_lock(cls, txo: 'Output', script_source: bytes) -> 'Input':
""" Create an input to spend time lock script."""
script = InputScript.redeem_time_lock_from_script(script_source)
return cls(txo.ref, script)
@property @property
def amount(self) -> int: def amount(self) -> int:
""" Amount this input adds to the transaction. """ """ Amount this input adds to the transaction. """
@ -937,6 +943,16 @@ class Transaction:
data = Output.add_purchase_data(Purchase(claim_id)) data = Output.add_purchase_data(Purchase(claim_id))
return cls.create([], [payment, data], funding_accounts, change_account) 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)
@property @property
def my_inputs(self): def my_inputs(self):
for txi in self.inputs: for txi in self.inputs:

View file

@ -1,8 +1,9 @@
from binascii import unhexlify from binascii import unhexlify
from lbry.testcase import CommandTestCase from lbry.testcase import CommandTestCase
from lbry.wallet.dewies import dewies_to_lbc from lbry.wallet.dewies import dewies_to_lbc, lbc_to_dewies
from lbry.wallet.account import DeterministicChannelKeyManager from lbry.wallet.account import DeterministicChannelKeyManager
from lbry.wallet.transaction import Transaction, Input, Output
def extract(d, keys): def extract(d, keys):
@ -289,3 +290,17 @@ class AccountManagement(CommandTestCase):
self.assertTrue(channel2c.has_private_key) self.assertTrue(channel2c.has_private_key)
self.assertTrue(channel3c.has_private_key) 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()
redeem = await self.blockchain.add_time_locked_address(210, address)
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)