forked from LBRYCommunity/lbry-sdk
split claim_abandon into stream_abandon and channel_abandon
This commit is contained in:
parent
4230812f82
commit
83411acfbd
4 changed files with 121 additions and 64 deletions
|
@ -1616,7 +1616,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
CLAIM_DOC = """
|
CLAIM_DOC = """
|
||||||
List, search and abandon all types of claims.
|
List and search all types of claims.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT)
|
@requires(WALLET_COMPONENT)
|
||||||
|
@ -1694,55 +1694,8 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
sort_claim_results(claims)
|
sort_claim_results(claims)
|
||||||
return {"items": claims, "total_pages": 1, "page": 1, "page_size": len(claims)}
|
return {"items": claims, "total_pages": 1, "page": 1, "page_size": len(claims)}
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
|
||||||
async def jsonrpc_claim_abandon(
|
|
||||||
self, claim_id=None, txid=None, nout=None, account_id=None,
|
|
||||||
preview=False, blocking=True):
|
|
||||||
"""
|
|
||||||
Abandon one of my channel or stream claims.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
claim_abandon [<claim_id> | --claim_id=<claim_id>]
|
|
||||||
[<txid> | --txid=<txid>] [<nout> | --nout=<nout>]
|
|
||||||
[--account_id=<account_id>]
|
|
||||||
[--preview] [--blocking]
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--claim_id=<claim_id> : (str) claim_id of the claim to abandon
|
|
||||||
--txid=<txid> : (str) txid of the claim to abandon
|
|
||||||
--nout=<nout> : (int) nout of the claim to abandon
|
|
||||||
--account_id=<account_id> : (str) id of the account to use
|
|
||||||
--preview : (bool) do not broadcast the transaction
|
|
||||||
--blocking : (bool) wait until abandon is in mempool
|
|
||||||
"""
|
|
||||||
account = self.get_account_or_default(account_id)
|
|
||||||
|
|
||||||
if txid is not None and nout is not None:
|
|
||||||
claims = await account.get_claims(**{'txo.txid': txid, 'txo.position': nout})
|
|
||||||
elif claim_id is not None:
|
|
||||||
claims = await account.get_claims(claim_id=claim_id)
|
|
||||||
else:
|
|
||||||
raise Exception('Must specify claim_id, or txid and nout')
|
|
||||||
|
|
||||||
if not claims:
|
|
||||||
raise Exception('No claim found for the specified claim_id or txid:nout')
|
|
||||||
|
|
||||||
tx = await Transaction.create(
|
|
||||||
[Input.spend(txo) for txo in claims], [], [account], account
|
|
||||||
)
|
|
||||||
|
|
||||||
if not preview:
|
|
||||||
await account.ledger.broadcast(tx)
|
|
||||||
await self.analytics_manager.send_claim_action('abandon')
|
|
||||||
if blocking:
|
|
||||||
await account.ledger.wait(tx)
|
|
||||||
else:
|
|
||||||
await account.ledger.release_tx(tx)
|
|
||||||
|
|
||||||
return tx
|
|
||||||
|
|
||||||
CHANNEL_DOC = """
|
CHANNEL_DOC = """
|
||||||
Create, update and list your channel claims.
|
Create, update, abandon and list your channel claims.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@deprecated('channel_create')
|
@deprecated('channel_create')
|
||||||
|
@ -1977,6 +1930,53 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
|
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
|
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||||
|
async def jsonrpc_channel_abandon(
|
||||||
|
self, claim_id=None, txid=None, nout=None, account_id=None,
|
||||||
|
preview=False, blocking=True):
|
||||||
|
"""
|
||||||
|
Abandon one of my channel claims.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
channel_abandon [<claim_id> | --claim_id=<claim_id>]
|
||||||
|
[<txid> | --txid=<txid>] [<nout> | --nout=<nout>]
|
||||||
|
[--account_id=<account_id>]
|
||||||
|
[--preview] [--blocking]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--claim_id=<claim_id> : (str) claim_id of the claim to abandon
|
||||||
|
--txid=<txid> : (str) txid of the claim to abandon
|
||||||
|
--nout=<nout> : (int) nout of the claim to abandon
|
||||||
|
--account_id=<account_id> : (str) id of the account to use
|
||||||
|
--preview : (bool) do not broadcast the transaction
|
||||||
|
--blocking : (bool) wait until abandon is in mempool
|
||||||
|
"""
|
||||||
|
account = self.get_account_or_default(account_id)
|
||||||
|
|
||||||
|
if txid is not None and nout is not None:
|
||||||
|
claims = await account.get_claims(**{'txo.txid': txid, 'txo.position': nout})
|
||||||
|
elif claim_id is not None:
|
||||||
|
claims = await account.get_claims(claim_id=claim_id)
|
||||||
|
else:
|
||||||
|
raise Exception('Must specify claim_id, or txid and nout')
|
||||||
|
|
||||||
|
if not claims:
|
||||||
|
raise Exception('No claim found for the specified claim_id or txid:nout')
|
||||||
|
|
||||||
|
tx = await Transaction.create(
|
||||||
|
[Input.spend(txo) for txo in claims], [], [account], account
|
||||||
|
)
|
||||||
|
|
||||||
|
if not preview:
|
||||||
|
await account.ledger.broadcast(tx)
|
||||||
|
await self.analytics_manager.send_claim_action('abandon')
|
||||||
|
if blocking:
|
||||||
|
await account.ledger.wait(tx)
|
||||||
|
else:
|
||||||
|
await account.ledger.release_tx(tx)
|
||||||
|
|
||||||
|
return tx
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT)
|
@requires(WALLET_COMPONENT)
|
||||||
def jsonrpc_channel_list(self, account_id=None, page=None, page_size=None):
|
def jsonrpc_channel_list(self, account_id=None, page=None, page_size=None):
|
||||||
"""
|
"""
|
||||||
|
@ -2037,7 +2037,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
return await self.wallet_manager.import_certificate_info(serialized_certificate_info)
|
return await self.wallet_manager.import_certificate_info(serialized_certificate_info)
|
||||||
|
|
||||||
STREAM_DOC = """
|
STREAM_DOC = """
|
||||||
Create, update, list and inspect your stream claims.
|
Create, update, abandon, list and inspect your stream claims.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT, STREAM_MANAGER_COMPONENT, BLOB_COMPONENT, DATABASE_COMPONENT,
|
@requires(WALLET_COMPONENT, STREAM_MANAGER_COMPONENT, BLOB_COMPONENT, DATABASE_COMPONENT,
|
||||||
|
@ -2466,6 +2466,53 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
|
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
|
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||||
|
async def jsonrpc_stream_abandon(
|
||||||
|
self, claim_id=None, txid=None, nout=None, account_id=None,
|
||||||
|
preview=False, blocking=True):
|
||||||
|
"""
|
||||||
|
Abandon one of my stream claims.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
stream_abandon [<claim_id> | --claim_id=<claim_id>]
|
||||||
|
[<txid> | --txid=<txid>] [<nout> | --nout=<nout>]
|
||||||
|
[--account_id=<account_id>]
|
||||||
|
[--preview] [--blocking]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--claim_id=<claim_id> : (str) claim_id of the claim to abandon
|
||||||
|
--txid=<txid> : (str) txid of the claim to abandon
|
||||||
|
--nout=<nout> : (int) nout of the claim to abandon
|
||||||
|
--account_id=<account_id> : (str) id of the account to use
|
||||||
|
--preview : (bool) do not broadcast the transaction
|
||||||
|
--blocking : (bool) wait until abandon is in mempool
|
||||||
|
"""
|
||||||
|
account = self.get_account_or_default(account_id)
|
||||||
|
|
||||||
|
if txid is not None and nout is not None:
|
||||||
|
claims = await account.get_claims(**{'txo.txid': txid, 'txo.position': nout})
|
||||||
|
elif claim_id is not None:
|
||||||
|
claims = await account.get_claims(claim_id=claim_id)
|
||||||
|
else:
|
||||||
|
raise Exception('Must specify claim_id, or txid and nout')
|
||||||
|
|
||||||
|
if not claims:
|
||||||
|
raise Exception('No claim found for the specified claim_id or txid:nout')
|
||||||
|
|
||||||
|
tx = await Transaction.create(
|
||||||
|
[Input.spend(txo) for txo in claims], [], [account], account
|
||||||
|
)
|
||||||
|
|
||||||
|
if not preview:
|
||||||
|
await account.ledger.broadcast(tx)
|
||||||
|
await self.analytics_manager.send_claim_action('abandon')
|
||||||
|
if blocking:
|
||||||
|
await account.ledger.wait(tx)
|
||||||
|
else:
|
||||||
|
await account.ledger.release_tx(tx)
|
||||||
|
|
||||||
|
return tx
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT)
|
@requires(WALLET_COMPONENT)
|
||||||
def jsonrpc_stream_list(self, account_id=None, page=None, page_size=None):
|
def jsonrpc_stream_list(self, account_id=None, page=None, page_size=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -81,7 +81,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
|
||||||
|
|
||||||
# After some soul searching Chris decides that his story needs more
|
# After some soul searching Chris decides that his story needs more
|
||||||
# heart and a better ending. He takes down the story and begins the rewrite.
|
# heart and a better ending. He takes down the story and begins the rewrite.
|
||||||
abandon = await self.out(self.daemon.jsonrpc_claim_abandon(claim_id, blocking=False))
|
abandon = await self.out(self.daemon.jsonrpc_stream_abandon(claim_id, blocking=False))
|
||||||
self.assertEqual(abandon['inputs'][0]['claim_id'], claim_id)
|
self.assertEqual(abandon['inputs'][0]['claim_id'], claim_id)
|
||||||
await self.confirm_tx(abandon['txid'])
|
await self.confirm_tx(abandon['txid'])
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
|
||||||
|
|
||||||
# But sadly Ramsey wasn't so pleased. It was hard for him to tell Chris...
|
# But sadly Ramsey wasn't so pleased. It was hard for him to tell Chris...
|
||||||
# Chris, though a bit heartbroken, abandoned the claim for now, but instantly started working on new hit lyrics
|
# Chris, though a bit heartbroken, abandoned the claim for now, but instantly started working on new hit lyrics
|
||||||
abandon = await self.out(self.daemon.jsonrpc_claim_abandon(txid=tx['txid'], nout=0, blocking=False))
|
abandon = await self.out(self.daemon.jsonrpc_stream_abandon(txid=tx['txid'], nout=0, blocking=False))
|
||||||
self.assertTrue(abandon['inputs'][0]['txid'], tx['txid'])
|
self.assertTrue(abandon['inputs'][0]['txid'], tx['txid'])
|
||||||
await self.confirm_tx(abandon['txid'])
|
await self.confirm_tx(abandon['txid'])
|
||||||
|
|
||||||
|
|
|
@ -379,7 +379,7 @@ class StreamCommands(CommandTestCase):
|
||||||
self.assertEqual(txs[0]['fee'], '-0.000184')
|
self.assertEqual(txs[0]['fee'], '-0.000184')
|
||||||
await self.assertBalance(self.account, '8.979709')
|
await self.assertBalance(self.account, '8.979709')
|
||||||
|
|
||||||
await self.claim_abandon(claim_id)
|
await self.stream_abandon(claim_id)
|
||||||
txs = await self.out(self.daemon.jsonrpc_transaction_list())
|
txs = await self.out(self.daemon.jsonrpc_transaction_list())
|
||||||
self.assertEqual(len(txs[0]['abandon_info']), 1)
|
self.assertEqual(len(txs[0]['abandon_info']), 1)
|
||||||
self.assertEqual(txs[0]['abandon_info'][0]['balance_delta'], '1.0')
|
self.assertEqual(txs[0]['abandon_info'][0]['balance_delta'], '1.0')
|
||||||
|
@ -392,7 +392,7 @@ class StreamCommands(CommandTestCase):
|
||||||
await self.assertBalance(self.account, '10.0')
|
await self.assertBalance(self.account, '10.0')
|
||||||
tx = await self.stream_create(bid='0.0001')
|
tx = await self.stream_create(bid='0.0001')
|
||||||
await self.assertBalance(self.account, '9.979793')
|
await self.assertBalance(self.account, '9.979793')
|
||||||
await self.claim_abandon(tx['outputs'][0]['claim_id'])
|
await self.stream_abandon(tx['outputs'][0]['claim_id'])
|
||||||
await self.assertBalance(self.account, '9.97968399')
|
await self.assertBalance(self.account, '9.97968399')
|
||||||
|
|
||||||
async def test_publish(self):
|
async def test_publish(self):
|
||||||
|
@ -422,8 +422,8 @@ class StreamCommands(CommandTestCase):
|
||||||
with self.assertRaisesRegex(Exception, "There are 2 claims for 'foo'"):
|
with self.assertRaisesRegex(Exception, "There are 2 claims for 'foo'"):
|
||||||
await self.daemon.jsonrpc_publish('foo')
|
await self.daemon.jsonrpc_publish('foo')
|
||||||
|
|
||||||
# abandon duplicate channel
|
# abandon duplicate stream
|
||||||
await self.claim_abandon(tx3['outputs'][0]['claim_id'])
|
await self.stream_abandon(tx3['outputs'][0]['claim_id'])
|
||||||
|
|
||||||
# publish to a channel
|
# publish to a channel
|
||||||
await self.channel_create('@abc')
|
await self.channel_create('@abc')
|
||||||
|
@ -458,7 +458,7 @@ class StreamCommands(CommandTestCase):
|
||||||
claims = await self.claim_search(claim_id=channel_id)
|
claims = await self.claim_search(claim_id=channel_id)
|
||||||
self.assertEqual(claims[0]['value'], value)
|
self.assertEqual(claims[0]['value'], value)
|
||||||
|
|
||||||
await self.claim_abandon(txid=txid, nout=0)
|
await self.channel_abandon(txid=txid, nout=0)
|
||||||
self.assertEqual(len(await self.claim_search(txid=txid, nout=0)), 0)
|
self.assertEqual(len(await self.claim_search(txid=txid, nout=0)), 0)
|
||||||
|
|
||||||
# search stream claims
|
# search stream claims
|
||||||
|
@ -481,9 +481,9 @@ class StreamCommands(CommandTestCase):
|
||||||
claims = await self.claim_search(channel_id=channel_id)
|
claims = await self.claim_search(channel_id=channel_id)
|
||||||
self.assertEqual(len(claims), 3)
|
self.assertEqual(len(claims), 3)
|
||||||
|
|
||||||
await self.claim_abandon(claim_id=claims[0]['claim_id'])
|
await self.stream_abandon(claim_id=claims[0]['claim_id'])
|
||||||
await self.claim_abandon(claim_id=claims[1]['claim_id'])
|
await self.stream_abandon(claim_id=claims[1]['claim_id'])
|
||||||
await self.claim_abandon(claim_id=claims[2]['claim_id'])
|
await self.stream_abandon(claim_id=claims[2]['claim_id'])
|
||||||
|
|
||||||
claims = await self.claim_search(channel_id=channel_id)
|
claims = await self.claim_search(channel_id=channel_id)
|
||||||
self.assertEqual(len(claims), 0)
|
self.assertEqual(len(claims), 0)
|
||||||
|
@ -518,7 +518,7 @@ class StreamCommands(CommandTestCase):
|
||||||
async def test_abandoned_channel_with_signed_claims(self):
|
async def test_abandoned_channel_with_signed_claims(self):
|
||||||
channel = (await self.channel_create('@abc', '1.0'))['outputs'][0]
|
channel = (await self.channel_create('@abc', '1.0'))['outputs'][0]
|
||||||
orphan_claim = await self.stream_create('on-channel-claim', '0.0001', channel_id=channel['claim_id'])
|
orphan_claim = await self.stream_create('on-channel-claim', '0.0001', channel_id=channel['claim_id'])
|
||||||
await self.claim_abandon(txid=channel['txid'], nout=0)
|
await self.channel_abandon(txid=channel['txid'], nout=0)
|
||||||
channel = (await self.channel_create('@abc', '1.0'))['outputs'][0]
|
channel = (await self.channel_create('@abc', '1.0'))['outputs'][0]
|
||||||
orphan_claim_id = orphan_claim['outputs'][0]['claim_id']
|
orphan_claim_id = orphan_claim['outputs'][0]['claim_id']
|
||||||
|
|
||||||
|
@ -531,7 +531,7 @@ class StreamCommands(CommandTestCase):
|
||||||
direct_uri = 'lbry://on-channel-claim#' + orphan_claim_id
|
direct_uri = 'lbry://on-channel-claim#' + orphan_claim_id
|
||||||
response = await self.resolve(direct_uri)
|
response = await self.resolve(direct_uri)
|
||||||
self.assertFalse(response[direct_uri]['claim']['signature_is_valid'])
|
self.assertFalse(response[direct_uri]['claim']['signature_is_valid'])
|
||||||
await self.claim_abandon(claim_id=orphan_claim_id)
|
await self.stream_abandon(claim_id=orphan_claim_id)
|
||||||
|
|
||||||
uri = 'lbry://@abc/on-channel-claim'
|
uri = 'lbry://@abc/on-channel-claim'
|
||||||
# now, claim something on this channel (it will update the invalid claim, but we save and forcefully restore)
|
# now, claim something on this channel (it will update the invalid claim, but we save and forcefully restore)
|
||||||
|
|
|
@ -186,6 +186,16 @@ class CommandTestCase(IntegrationTestCase):
|
||||||
await self.on_transaction_dict(claim)
|
await self.on_transaction_dict(claim)
|
||||||
return claim
|
return claim
|
||||||
|
|
||||||
|
async def stream_abandon(self, *args, confirm=True, **kwargs):
|
||||||
|
if 'blocking' not in kwargs:
|
||||||
|
kwargs['blocking'] = False
|
||||||
|
tx = await self.out(self.daemon.jsonrpc_stream_abandon(*args, **kwargs))
|
||||||
|
if confirm:
|
||||||
|
await self.on_transaction_dict(tx)
|
||||||
|
await self.generate(1)
|
||||||
|
await self.on_transaction_dict(tx)
|
||||||
|
return tx
|
||||||
|
|
||||||
async def publish(self, name, *args, confirm=True, **kwargs):
|
async def publish(self, name, *args, confirm=True, **kwargs):
|
||||||
claim = await self.out(self.daemon.jsonrpc_publish(name, *args, **kwargs))
|
claim = await self.out(self.daemon.jsonrpc_publish(name, *args, **kwargs))
|
||||||
self.assertEqual(claim['outputs'][0]['name'], name)
|
self.assertEqual(claim['outputs'][0]['name'], name)
|
||||||
|
@ -213,10 +223,10 @@ class CommandTestCase(IntegrationTestCase):
|
||||||
await self.on_transaction_dict(channel)
|
await self.on_transaction_dict(channel)
|
||||||
return channel
|
return channel
|
||||||
|
|
||||||
async def claim_abandon(self, *args, confirm=True, **kwargs):
|
async def channel_abandon(self, *args, confirm=True, **kwargs):
|
||||||
if 'blocking' not in kwargs:
|
if 'blocking' not in kwargs:
|
||||||
kwargs['blocking'] = False
|
kwargs['blocking'] = False
|
||||||
tx = await self.out(self.daemon.jsonrpc_claim_abandon(*args, **kwargs))
|
tx = await self.out(self.daemon.jsonrpc_channel_abandon(*args, **kwargs))
|
||||||
if confirm:
|
if confirm:
|
||||||
await self.on_transaction_dict(tx)
|
await self.on_transaction_dict(tx)
|
||||||
await self.generate(1)
|
await self.generate(1)
|
||||||
|
|
Loading…
Reference in a new issue